using System.ComponentModel;
using System.Data;
using System.Data.Common;
+#if !MOBILE
using System.EnterpriseServices;
+#endif
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Xml;
+#if NET_2_0
+using System.Collections.Generic;
+#endif
-namespace System.Data.SqlClient {
+namespace System.Data.SqlClient
+{
[DefaultEvent ("InfoMessage")]
#if NET_2_0
public sealed class SqlConnection : DbConnection, IDbConnection, ICloneable
#endif // NET_2_0
{
#region Fields
- bool disposed = false;
+
+ bool disposed;
// The set of SQL connection pools
- static TdsConnectionPoolManager sqlConnectionPools = new TdsConnectionPoolManager (TdsVersion.tds70);
+ static TdsConnectionPoolManager sqlConnectionPools = new TdsConnectionPoolManager (TdsVersion.tds80);
+#if NET_2_0
+ const int DEFAULT_PACKETSIZE = 8000;
+ const int MAX_PACKETSIZE = 32768;
+#else
+ const int DEFAULT_PACKETSIZE = 8192;
+ const int MAX_PACKETSIZE = 32767;
+#endif
+ const int MIN_PACKETSIZE = 512;
+ const int DEFAULT_CONNECTIONTIMEOUT = 15;
+ const int DEFAULT_MAXPOOLSIZE = 100;
+ const int MIN_MAXPOOLSIZE = 1;
+ const int DEFAULT_MINPOOLSIZE = 0;
+ const int DEFAULT_PORT = 1433;
// The current connection pool
TdsConnectionPool pool;
// The connection string that identifies this connection
- string connectionString = null;
+ string connectionString;
// The transaction object for the current transaction
- SqlTransaction transaction = null;
+ SqlTransaction transaction;
// Connection parameters
- TdsConnectionParameters parms = new TdsConnectionParameters ();
- NameValueCollection connStringParameters = null;
+ TdsConnectionParameters parms;
bool connectionReset;
bool pooling;
string dataSource;
int minPoolSize;
int maxPoolSize;
int packetSize;
- int port = 1433;
+ int port;
bool fireInfoMessageEventOnUserErrors;
bool statisticsEnabled;
-
+
// The current state
ConnectionState state = ConnectionState.Closed;
- SqlDataReader dataReader = null;
- XmlReader xmlReader = null;
+ SqlDataReader dataReader;
+ XmlReader xmlReader;
// The TDS object
- ITds tds;
+ Tds tds;
#endregion // Fields
#region Constructors
- public SqlConnection ()
- : this (String.Empty)
+ public SqlConnection () : this (null)
{
}
public SqlConnection (string connectionString)
{
- Init (connectionString);
- }
-
- private void Init (string connectionString)
- {
- connectionTimeout = 15; // default timeout
- dataSource = ""; // default datasource
- packetSize = 8192; // default packetsize
- ConnectionString = connectionString;
+ ConnectionString = connectionString;
}
#endregion // Constructors
[EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
[RecommendedAsConfigurable (true)]
[RefreshProperties (RefreshProperties.All)]
- public
+ public
#if NET_2_0
override
#endif // NET_2_0
string ConnectionString {
- get { return connectionString; }
+ get {
+ if (connectionString == null)
+ return string.Empty;
+ return connectionString;
+ }
[MonoTODO("persist security info, encrypt, enlist keyword not implemented")]
set {
if (state == ConnectionState.Open)
throw new InvalidOperationException ("Not Allowed to change ConnectionString property while Connection state is OPEN");
- SetConnectionString (value);
+ SetConnectionString (value);
}
}
[DataSysDescription ("Current connection timeout value, 'Connect Timeout=X' in the ConnectionString.")]
#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
- public
+ public
#if NET_2_0
override
#endif // NET_2_0
[DataSysDescription ("Current SQL Server database, 'Initial Catalog=X' in the connection string.")]
#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
- public
+ public
#if NET_2_0
override
#endif // NET_2_0
[Browsable(true)]
#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
- public
+ public
#if NET_2_0
override
#endif // NET_2_0
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public int PacketSize {
get {
- if (State == ConnectionState.Open)
- return ((Tds)tds).PacketSize ;
- return packetSize;
+ if (State == ConnectionState.Open)
+ return ((Tds) tds).PacketSize;
+ return packetSize;
}
}
[DataSysDescription ("Version of the SQL Server accessed by the SqlConnection.")]
#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
- public
+ public
#if NET_2_0
override
#endif // NET_2_0
string ServerVersion {
get {
if (state == ConnectionState.Closed)
- throw new InvalidOperationException ("Invalid Operation.The Connection is Closed");
+ throw ExceptionHelper.ConnectionClosed ();
else
return tds.ServerVersion;
}
[DataSysDescription ("The ConnectionState indicating whether the connection is open or closed.")]
#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
- public
+ public
#if NET_2_0
override
#endif // NET_2_0
get { return state; }
}
- internal ITds Tds {
+ internal Tds Tds {
get { return tds; }
}
private void ErrorHandler (object sender, TdsInternalErrorMessageEventArgs e)
{
+ try {
+ if (!tds.IsConnected)
+ Close ();
+ } catch {
+ try {
+ Close ();
+ } catch {
+ }
+ }
throw new SqlException (e.Class, e.LineNumber, e.Message, e.Number, e.Procedure, e.Server, "Mono SqlClient Data Provider", e.State);
}
#region Methods
- internal string GetConnStringKeyValue (params string [] keys)
- {
- if (connStringParameters == null || connStringParameters.Count == 0)
- return "";
- foreach (string key in keys) {
- string value = connStringParameters [key];
- if (value != null)
- return value;
- }
-
- return "";
- }
-
public new SqlTransaction BeginTransaction ()
{
return BeginTransaction (IsolationLevel.ReadCommitted, String.Empty);
public SqlTransaction BeginTransaction (IsolationLevel iso, string transactionName)
{
if (state == ConnectionState.Closed)
- throw new InvalidOperationException ("The connection is not open.");
+ throw ExceptionHelper.ConnectionClosed ();
if (transaction != null)
throw new InvalidOperationException ("SqlConnection does not support parallel transactions.");
- if (iso == IsolationLevel.Chaos)
- throw new ArgumentException ("Invalid IsolationLevel parameter: must be ReadCommitted, ReadUncommitted, RepeatableRead, or Serializable.");
-
string isolevel = String.Empty;
switch (iso) {
case IsolationLevel.ReadUncommitted:
isolevel = "SERIALIZABLE";
break;
case IsolationLevel.ReadCommitted:
- default:
isolevel = "READ COMMITTED";
break;
+#if NET_2_0
+ case IsolationLevel.Snapshot:
+ isolevel = "SNAPSHOT";
+ break;
+ case IsolationLevel.Unspecified:
+ iso = IsolationLevel.ReadCommitted;
+ isolevel = "READ COMMITTED";
+ break;
+ case IsolationLevel.Chaos:
+ throw new ArgumentOutOfRangeException ("IsolationLevel",
+ string.Format (CultureInfo.CurrentCulture,
+ "The IsolationLevel enumeration " +
+ "value, {0}, is not supported by " +
+ "the .Net Framework SqlClient " +
+ "Data Provider.", (int) iso));
+#endif
+ default:
+#if NET_2_0
+ throw new ArgumentOutOfRangeException ("IsolationLevel",
+ string.Format (CultureInfo.CurrentCulture,
+ "The IsolationLevel enumeration value, {0}, is invalid.",
+ (int) iso));
+#else
+ throw new ArgumentException ("Invalid IsolationLevel parameter: must be ReadCommitted, ReadUncommitted, RepeatableRead, or Serializable.");
+#endif
}
tds.Execute (String.Format ("SET TRANSACTION ISOLATION LEVEL {0};BEGIN TRANSACTION {1}", isolevel, transactionName));
return transaction;
}
- public
+ public
#if NET_2_0
override
#endif // NET_2_0
- void ChangeDatabase (string database)
+ void ChangeDatabase (string database)
{
if (!IsValidDatabaseName (database))
throw new ArgumentException (String.Format ("The database name {0} is not valid.", database));
private void ChangeState (ConnectionState currentState)
{
+ if (currentState == state)
+ return;
+
ConnectionState originalState = state;
state = currentState;
OnStateChange (CreateStateChangeEvent (originalState, currentState));
}
- public
+ public
#if NET_2_0
override
#endif // NET_2_0
- void Close ()
+ void Close ()
{
if (transaction != null && transaction.IsOpen)
transaction.Rollback ();
if (tds != null && tds.IsConnected) {
if (pooling && tds.Pooling) {
-#if NET_2_0
- if(pool != null) pool.ReleaseConnection (ref tds);
-#else
- if(pool != null) pool.ReleaseConnection (tds);
-#endif
- }else
- if(tds != null) tds.Disconnect ();
+ if (pool != null) {
+ pool.ReleaseConnection (tds);
+ pool = null;
+ }
+ } else {
+ tds.Disconnect ();
+ }
}
if (tds != null) {
ChangeState (ConnectionState.Closed);
}
- public new SqlCommand CreateCommand ()
+ public new SqlCommand CreateCommand ()
{
SqlCommand command = new SqlCommand ();
command.Connection = this;
return new StateChangeEventArgs (originalState, currentState);
}
- protected override void Dispose (bool disposing)
+ protected override void Dispose (bool disposing)
{
- if (disposed)
- return;
-
try {
- if (disposing) {
+ if (disposing && !disposed) {
if (State == ConnectionState.Open)
Close ();
- ConnectionString = "";
- SetDefaultConnectionParameters (this.connStringParameters);
+ ConnectionString = null;
}
} finally {
disposed = true;
}
}
+#if !MOBILE
[MonoTODO ("Not sure what this means at present.")]
public void EnlistDistributedTransaction (ITransaction transaction)
{
throw new NotImplementedException ();
}
+#endif
object ICloneable.Clone ()
{
}
#if NET_2_0
- protected override DbTransaction BeginDbTransaction (IsolationLevel level)
+ protected override DbTransaction BeginDbTransaction (IsolationLevel isolationLevel)
{
- return (DbTransaction)BeginTransaction (level);
+ return BeginTransaction (isolationLevel);
}
protected override DbCommand CreateDbCommand ()
}
#endif
- public
+ public
#if NET_2_0
override
#endif // NET_2_0
- void Open ()
+ void Open ()
{
- string serverName = "";
+ string serverName = string.Empty;
if (state == ConnectionState.Open)
throw new InvalidOperationException ("The Connection is already Open (State=Open)");
if (!pooling) {
if(!ParseDataSource (dataSource, out port, out serverName))
throw new SqlException(20, 0, "SQL Server does not exist or access denied.", 17, "ConnectionOpen (Connect()).", dataSource, parms.ApplicationName, 0);
- tds = new Tds70 (serverName, port, PacketSize, ConnectionTimeout);
+ tds = new Tds80 (serverName, port, PacketSize, ConnectionTimeout);
+ tds.Pooling = false;
}
else {
if(!ParseDataSource (dataSource, out port, out serverName))
pool.ReleaseConnection (tds);
throw;
}
- } else if (connectionReset) {
- tds.Reset ();
}
disposed = false; // reset this, so using () would call Close ().
ChangeState (ConnectionState.Open);
}
- private bool ParseDataSource (string theDataSource, out int thePort, out string theServerName)
+ private bool ParseDataSource (string theDataSource, out int thePort, out string theServerName)
{
- theServerName = "";
- string theInstanceName = "";
+ theServerName = string.Empty;
+ string theInstanceName = string.Empty;
if (theDataSource == null)
throw new ArgumentException("Format of initialization string does not conform to specifications");
- thePort = 1433; // default TCP port for SQL Server
+ thePort = DEFAULT_PORT; // default TCP port for SQL Server
bool success = true;
int idx = 0;
- if ((idx = theDataSource.IndexOf (",")) > -1) {
+ if ((idx = theDataSource.IndexOf (',')) > -1) {
theServerName = theDataSource.Substring (0, idx);
string p = theDataSource.Substring (idx + 1);
thePort = Int32.Parse (p);
- }
- else if ((idx = theDataSource.IndexOf ("\\")) > -1) {
+ } else if ((idx = theDataSource.IndexOf ('\\')) > -1) {
theServerName = theDataSource.Substring (0, idx);
theInstanceName = theDataSource.Substring (idx + 1);
+
// do port discovery via UDP port 1434
port = DiscoverTcpPortViaSqlMonitor (theServerName, theInstanceName);
if (port == -1)
success = false;
- }
- else if (theDataSource == "" || theDataSource == "(local)")
- theServerName = "localhost";
- else
+ } else
theServerName = theDataSource;
- if ((idx = theServerName.IndexOf ("tcp:")) > -1) {
+ if (theServerName.Length == 0 || theServerName == "(local)" || theServerName == ".")
+ theServerName = "localhost";
+
+ if ((idx = theServerName.IndexOf ("tcp:")) > -1)
theServerName = theServerName.Substring (idx + 4);
- }
return success;
}
private bool ConvertIntegratedSecurity (string value)
{
- if (value.ToUpper() == "SSPI")
- {
+ if (value.ToUpper() == "SSPI")
return true;
- }
- return ConvertToBoolean("integrated security", value);
+ return ConvertToBoolean ("integrated security", value, false);
}
- private bool ConvertToBoolean(string key, string value)
+ private bool ConvertToBoolean (string key, string value, bool defaultValue)
{
- string upperValue = value.ToUpper();
+ if (value.Length == 0)
+ return defaultValue;
- if (upperValue == "TRUE" ||upperValue == "YES")
- {
+ string upperValue = value.ToUpper ();
+
+ if (upperValue == "TRUE" || upperValue == "YES")
return true;
- }
else if (upperValue == "FALSE" || upperValue == "NO")
- {
return false;
- }
- throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
+ throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
"Invalid value \"{0}\" for key '{1}'.", value, key));
}
- private int ConvertToInt32(string key, string value)
+ private int ConvertToInt32 (string key, string value, int defaultValue)
{
- try
- {
- return int.Parse(value);
+ if (value.Length == 0)
+ return defaultValue;
+
+ try {
+ return int.Parse (value);
} catch (Exception ex) {
- throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
- "Invalid value \"{0}\" for key '{1}'.", value, key));
+ throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
+ "Invalid value \"{0}\" for key '{1}'.", value, key), ex);
}
}
- private int DiscoverTcpPortViaSqlMonitor(string ServerName, string InstanceName)
+ private int DiscoverTcpPortViaSqlMonitor (string ServerName, string InstanceName)
{
SqlMonitorSocket msock;
msock = new SqlMonitorSocket (ServerName, InstanceName);
- int SqlServerPort = msock.DiscoverTcpPort ();
+ int SqlServerPort = msock.DiscoverTcpPort (ConnectionTimeout);
msock = null;
return SqlServerPort;
}
void SetConnectionString (string connectionString)
{
- NameValueCollection parameters = new NameValueCollection ();
- SetDefaultConnectionParameters (parameters);
+ SetDefaultConnectionParameters ();
if ((connectionString == null) || (connectionString.Trim().Length == 0)) {
this.connectionString = connectionString;
- this.connStringParameters = parameters;
return;
}
else {
if (name != String.Empty && name != null) {
value = sb.ToString ();
- SetProperties (name.ToUpper ().Trim() , value);
- parameters [name.ToUpper ().Trim ()] = value.Trim ();
+ SetProperties (name.ToLower ().Trim() , value);
}
else if (sb.Length != 0)
throw new ArgumentException ("Format of initialization string does not conform to specifications");
}
}
+ if (minPoolSize > maxPoolSize)
+ throw new ArgumentException ("Invalid value for "
+ + "'min pool size' or 'max pool size'; "
+ + "'min pool size' must not be greater "
+ + "than 'max pool size'.");
+
connectionString = connectionString.Substring (0 , connectionString.Length-1);
this.connectionString = connectionString;
- this.connStringParameters = parameters;
}
- void SetDefaultConnectionParameters (NameValueCollection parameters)
+ void SetDefaultConnectionParameters ()
{
- parms.Reset ();
- dataSource = "";
- connectionTimeout= 15;
+ if (parms == null)
+ parms = new TdsConnectionParameters ();
+ else
+ parms.Reset ();
+ dataSource = string.Empty;
+ connectionTimeout = DEFAULT_CONNECTIONTIMEOUT;
connectionReset = true;
pooling = true;
- maxPoolSize = 100;
- minPoolSize = 0;
- packetSize = 8192;
-
- parameters["APPLICATION NAME"] = "Mono SqlClient Data Provider";
- parameters["CONNECT TIMEOUT"] = "15";
- parameters["CONNECTION LIFETIME"] = "0";
- parameters["CONNECTION RESET"] = "true";
- parameters["ENLIST"] = "true";
- parameters["INTEGRATED SECURITY"] = "false";
- parameters["INITIAL CATALOG"] = "";
- parameters["MAX POOL SIZE"] = "100";
- parameters["MIN POOL SIZE"] = "0";
- parameters["NETWORK LIBRARY"] = "dbmssocn";
- parameters["PACKET SIZE"] = "8192";
- parameters["PERSIST SECURITY INFO"] = "false";
- parameters["POOLING"] = "true";
- parameters["WORKSTATION ID"] = Dns.GetHostName();
+ maxPoolSize = DEFAULT_MAXPOOLSIZE;
+ minPoolSize = DEFAULT_MINPOOLSIZE;
+ packetSize = DEFAULT_PACKETSIZE;
+ port = DEFAULT_PORT;
#if NET_2_0
async = false;
- parameters ["ASYNCHRONOUS PROCESSING"] = "false";
#endif
}
-
+
private void SetProperties (string name , string value)
{
-
- switch (name)
- {
- case "APP" :
- case "APPLICATION NAME" :
+ switch (name) {
+ case "app" :
+ case "application name" :
parms.ApplicationName = value;
break;
- case "ATTACHDBFILENAME" :
- case "EXTENDED PROPERTIES" :
- case "INITIAL FILE NAME" :
+ case "attachdbfilename" :
+ case "extended properties" :
+ case "initial file name" :
parms.AttachDBFileName = value;
break;
- case "TIMEOUT" :
- case "CONNECT TIMEOUT" :
- case "CONNECTION TIMEOUT" :
- int tmpTimeout = ConvertToInt32 ("connection timeout", value);
+ case "timeout" :
+ case "connect timeout" :
+ case "connection timeout" :
+ int tmpTimeout = ConvertToInt32 ("connect timeout", value,
+ DEFAULT_CONNECTIONTIMEOUT);
if (tmpTimeout < 0)
- throw new ArgumentException ("Invalid CONNECTION TIMEOUT .. Must be an integer >=0 ");
+ throw new ArgumentException ("Invalid 'connect timeout'. Must be an integer >=0 ");
else
connectionTimeout = tmpTimeout;
break;
- case "CONNECTION LIFETIME" :
+ case "connection lifetime" :
break;
- case "CONNECTION RESET" :
- connectionReset = ConvertToBoolean ("connection reset", value);
+ case "connection reset" :
+ connectionReset = ConvertToBoolean ("connection reset", value, true);
break;
- case "LANGUAGE" :
- case "CURRENT LANGUAGE" :
+ case "language" :
+ case "current language" :
parms.Language = value;
break;
- case "DATA SOURCE" :
- case "SERVER" :
- case "ADDRESS" :
- case "ADDR" :
- case "NETWORK ADDRESS" :
+ case "data source" :
+ case "server" :
+ case "address" :
+ case "addr" :
+ case "network address" :
dataSource = value;
break;
- case "ENCRYPT":
- if (ConvertToBoolean("encrypt", value))
- {
+ case "encrypt":
+ if (ConvertToBoolean (name, value, false))
throw new NotImplementedException("SSL encryption for"
+ " data sent between client and server is not"
+ " implemented.");
- }
break;
- case "ENLIST" :
- if (!ConvertToBoolean("enlist", value))
- {
+ case "enlist" :
+ if (!ConvertToBoolean (name, value, true))
throw new NotImplementedException("Disabling the automatic"
+ " enlistment of connections in the thread's current"
+ " transaction context is not implemented.");
- }
break;
- case "INITIAL CATALOG" :
- case "DATABASE" :
+ case "initial catalog" :
+ case "database" :
parms.Database = value;
break;
- case "INTEGRATED SECURITY" :
- case "TRUSTED_CONNECTION" :
+ case "integrated security" :
+ case "trusted_connection" :
parms.DomainLogin = ConvertIntegratedSecurity(value);
break;
- case "MAX POOL SIZE" :
- int tmpMaxPoolSize = ConvertToInt32 ("max pool size" , value);
- if (tmpMaxPoolSize < 0)
- throw new ArgumentException ("Invalid MAX POOL SIZE. Must be a intger >= 0");
+ case "max pool size" :
+ int tmpMaxPoolSize = ConvertToInt32 (name, value, DEFAULT_MAXPOOLSIZE);
+ if (tmpMaxPoolSize < MIN_MAXPOOLSIZE)
+ throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
+ "Invalid '{0}'. The value must be greater than {1}.",
+ name, MIN_MAXPOOLSIZE));
else
- maxPoolSize = tmpMaxPoolSize;
+ maxPoolSize = tmpMaxPoolSize;
break;
- case "MIN POOL SIZE" :
- int tmpMinPoolSize = ConvertToInt32 ("min pool size" , value);
+ case "min pool size" :
+ int tmpMinPoolSize = ConvertToInt32 (name, value, DEFAULT_MINPOOLSIZE);
if (tmpMinPoolSize < 0)
- throw new ArgumentException ("Invalid MIN POOL SIZE. Must be a intger >= 0");
+ throw new ArgumentException ("Invalid 'min pool size'. Must be a integer >= 0");
else
minPoolSize = tmpMinPoolSize;
break;
-#if NET_2_0
- case "MULTIPLEACTIVERESULTSETS":
+#if NET_2_0
+ case "multipleactiveresultsets":
+ // FIXME: not implemented
+ ConvertToBoolean (name, value, false);
break;
- case "ASYNCHRONOUS PROCESSING" :
- case "ASYNC" :
- async = ConvertToBoolean (name, value);
+ case "asynchronous processing" :
+ case "async" :
+ async = ConvertToBoolean (name, value, false);
break;
-#endif
- case "NET" :
- case "NETWORK" :
- case "NETWORK LIBRARY" :
+#endif
+ case "net" :
+ case "network" :
+ case "network library" :
if (!value.ToUpper ().Equals ("DBMSSOCN"))
throw new ArgumentException ("Unsupported network library.");
break;
- case "PACKET SIZE" :
- int tmpPacketSize = ConvertToInt32 ("packet size", value);
- if (tmpPacketSize < 512 || tmpPacketSize > 32767)
- throw new ArgumentException ("Invalid PACKET SIZE. The integer must be between 512 and 32767");
+ case "packet size" :
+ int tmpPacketSize = ConvertToInt32 (name, value, DEFAULT_PACKETSIZE);
+ if (tmpPacketSize < MIN_PACKETSIZE || tmpPacketSize > MAX_PACKETSIZE)
+ throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
+ "Invalid 'Packet Size'. The value must be between {0} and {1}.",
+ MIN_PACKETSIZE, MAX_PACKETSIZE));
else
packetSize = tmpPacketSize;
break;
- case "PASSWORD" :
- case "PWD" :
+ case "password" :
+ case "pwd" :
parms.Password = value;
break;
- case "PERSISTSECURITYINFO" :
- case "PERSIST SECURITY INFO" :
+ case "persistsecurityinfo" :
+ case "persist security info" :
// FIXME : not implemented
// throw new NotImplementedException ();
break;
- case "POOLING" :
- pooling = ConvertToBoolean("pooling", value);
+ case "pooling" :
+ pooling = ConvertToBoolean (name, value, true);
break;
- case "UID" :
- case "USER" :
- case "USER ID" :
+ case "uid" :
+ case "user" :
+ case "user id" :
parms.User = value;
break;
- case "WSID" :
- case "WORKSTATION ID" :
+ case "wsid" :
+ case "workstation id" :
parms.Hostname = value;
break;
+#if NET_2_0
+ case "user instance":
+ userInstance = ConvertToBoolean (name, value, false);
+ break;
+#endif
default :
- throw new ArgumentException("Keyword not supported :"+name);
+ throw new ArgumentException("Keyword not supported : '" + name + "'.");
}
}
static bool IsValidDatabaseName (string database)
{
- if ( database == null || database.Trim() == String.Empty || database.Length > 128)
+ if ( database == null || database.Trim().Length == 0 || database.Length > 128)
return false ;
if (database[0] == '"' && database[database.Length] == '"')
}
#endif
- private sealed class SqlMonitorSocket : UdpClient
+ private sealed class SqlMonitorSocket : UdpClient
{
// UDP port that the SQL Monitor listens
private static readonly int SqlMonitorUdpPort = 1434;
instance = InstanceName;
}
- internal int DiscoverTcpPort ()
+ internal int DiscoverTcpPort (int timeoutSeconds)
{
int SqlServerTcpPort;
Client.Blocking = false;
Byte[] rawrq = new Byte [instance.Length + 1];
rawrq[0] = 4;
enc.GetBytes (instance, 0, instance.Length, rawrq, 1);
- int bytes = Send (rawrq, rawrq.Length);
+ Send (rawrq, rawrq.Length);
if (!Active)
return -1; // Error
bool result;
- result = Client.Poll (100, SelectMode.SelectRead);
+ long timeout = timeoutSeconds * 1000000;
+ result = Client.Poll ((int)timeout, SelectMode.SelectRead);
if (result == false)
return -1; // Error
for (int i = 0; i < rawtokens.Length / 2 && i < 256; i++) {
data [rawtokens [i * 2]] = rawtokens [ i * 2 + 1];
}
- if (!data.ContainsKey ("tcp"))
- throw new NotImplementedException ("Only TCP/IP is supported.");
+
+ if (!data.ContainsKey ("tcp")) {
+ string msg = "Mono does not support names pipes or shared memory "
+ + "for connecting to SQL Server. Please enable the TCP/IP "
+ + "protocol.";
+ throw new NotImplementedException (msg);
+ }
SqlServerTcpPort = int.Parse ((string) data ["tcp"]);
Close ();
}
#if NET_2_0
- struct ColumnInfo {
+ struct ColumnInfo
+ {
public string name;
public Type type;
+
public ColumnInfo (string name, Type type)
{
this.name = name; this.type = type;
new object [] {"Databases", 1, 1},
new object [] {"Tables", 4, 3},
new object [] {"Columns", 4, 4},
+ new object [] {"StructuredTypeMembers", 4, 4},
new object [] {"Views", 3, 3},
new object [] {"ViewColumns", 4, 4},
new object [] {"ProcedureParameters", 4, 1},
static public DataTable Instance {
get {
if (instance == null) {
- instance = new DataTable ("GetSchema");
+ instance = new DataTable ("MetaDataCollections");
foreach (ColumnInfo c in columns)
instance.Columns.Add (c.name, c.type);
foreach (object [] row in rows)
}
}
+ static class DataSourceInformation
+ {
+ static readonly ColumnInfo [] columns = {
+ new ColumnInfo ("CompositeIdentifierSeparatorPattern", typeof (string)),
+ new ColumnInfo ("DataSourceProductName", typeof(string)),
+ new ColumnInfo ("DataSourceProductVersion", typeof(string)),
+ new ColumnInfo ("DataSourceProductVersionNormalized", typeof(string)),
+ new ColumnInfo ("GroupByBehavior", typeof(GroupByBehavior)),
+ new ColumnInfo ("IdentifierPattern", typeof(string)),
+ new ColumnInfo ("IdentifierCase", typeof(IdentifierCase)),
+ new ColumnInfo ("OrderByColumnsInSelect", typeof(bool)),
+ new ColumnInfo ("ParameterMarkerFormat", typeof(string)),
+ new ColumnInfo ("ParameterMarkerPattern", typeof(string)),
+ new ColumnInfo ("ParameterNameMaxLength", typeof(int)),
+ new ColumnInfo ("ParameterNamePattern", typeof(string)),
+ new ColumnInfo ("QuotedIdentifierPattern", typeof(string)),
+ new ColumnInfo ("QuotedIdentifierCase", typeof(IdentifierCase)),
+ new ColumnInfo ("StatementSeparatorPattern", typeof(string)),
+ new ColumnInfo ("StringLiteralPattern", typeof(string)),
+ new ColumnInfo ("SupportedJoinOperators", typeof(SupportedJoinOperators))
+ };
+
+ static public DataTable GetInstance (SqlConnection conn)
+ {
+ DataTable table = new DataTable ("DataSourceInformation");
+ foreach (ColumnInfo c in columns)
+ table.Columns.Add (c.name, c.type);
+ DataRow row = table.NewRow ();
+ row [0] = "\\.";
+ row [1] = "Microsoft SQL Server";
+ row [2] = conn.ServerVersion;;
+ row [3] = conn.ServerVersion;;
+ row [4] = GroupByBehavior.Unrelated;
+ row [5] = @"(^\[\p{Lo}\p{Lu}\p{Ll}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Nd}@$#_]*$)|(^\[[^\]\0]|\]\]+\]$)|(^\""[^\""\0]|\""\""+\""$)";
+ row [6] = IdentifierCase.Insensitive; // FIXME: obtain this from SQL Server
+ row [7] = false;
+ row [8] = "{0}";
+ row [9] = @"@[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)";
+ row [10] = 128;
+ row [11] = @"^[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)";
+ row [12] = @"(([^\[]|\]\])*)";
+ row [13] = IdentifierCase.Insensitive; // FIXME: obtain this from SQL Server
+ row [14] =";";
+ row [15] = "'(([^']|'')*)'";
+ row [16] = (SupportedJoinOperators.FullOuter | SupportedJoinOperators.Inner |
+ SupportedJoinOperators.LeftOuter | SupportedJoinOperators.RightOuter);
+ table.Rows.Add (row);
+ return table;
+ }
+ }
+
static class DataTypes
{
static readonly ColumnInfo [] columns = {
null, "0x", null},
new object [] {"uniqueidentifier", 14, 16, "uniqueidentifier", null,
"System.Guid", false, true, false, true, false, false, true,
- true, false, null, null, null, false, null, "'", "'"}
+ true, false, null, null, null, false, null, "'", "'"},
+ new object [] {"date", 31, 3L, "date", DBNull.Value,
+ "System.DateTime", false, false, false, true, true, false,
+ true, true, true, DBNull.Value, DBNull.Value, DBNull.Value,
+ false, DBNull.Value, "{ts '", "'}"},
+ new object [] {"time", 32, 5L, "time({0})", "scale",
+ "System.TimeSpan", false, false, false, false, false, false,
+ true, true, true, DBNull.Value, (short) 7, (short) 0,
+ false, DBNull.Value, "{ts '", "'}"},
+ new object [] {"datetime2", 33, 8L, "datetime2({0})", "scale",
+ "System.DateTime", false, true, false, false, false, false,
+ true, true, true, DBNull.Value, (short) 7, (short) 0,
+ false, DBNull.Value, "{ts '", "'}"},
+ new object [] {"datetimeoffset", 34, 10L, "datetimeoffset({0})",
+ "scale", "System.DateTimeOffset", false, true, false, false,
+ false, false, true, true, true, DBNull.Value, (short) 7, (short) 0,
+ false, DBNull.Value, "{ts '", "'}"}
};
static DataTable instance;
new object [] {"Columns", "Table", "@Table", "TABLE_NAME", 3},
new object [] {"Columns", "Column", "@Column", "COLUMN_NAME", 4},
+ new object [] {"StructuredTypeMembers", "Catalog", "@Catalog", "TYPE_CATALOG", 1},
+ new object [] {"StructuredTypeMembers", "Owner", "@Owner", "TYPE_SCHEMA", 2},
+ new object [] {"StructuredTypeMembers", "Type", "@Type", "TYPE_NAME", 3},
+ new object [] {"StructuredTypeMembers", "Member", "@Member", "MEMBER_NAME", 4},
+
new object [] {"Views", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
new object [] {"Views", "Owner", "@Owner", "TABLE_SCHEMA", 2},
new object [] {"Views", "Table", "@Table", "TABLE_NAME", 3},
new object [] {"Procedures", "Name", "@Name", "SPECIFIC_NAME", 3},
new object [] {"Procedures", "Type", "@Type", "ROUTINE_TYPE", 4},
- new object [] {"IndexColumns", "Catalog", "@Catalog", "db_name(}", 1},
- new object [] {"IndexColumns", "Owner", "@Owner", "user_name(}", 2},
+ new object [] {"IndexColumns", "Catalog", "@Catalog", "db_name()", 1},
+ new object [] {"IndexColumns", "Owner", "@Owner", "user_name()", 2},
new object [] {"IndexColumns", "Table", "@Table", "o.name", 3},
new object [] {"IndexColumns", "ConstraintName", "@ConstraintName", "x.name", 4},
new object [] {"IndexColumns", "Column", "@Column", "c.name", 5},
- new object [] {"Indexes", "Catalog", "@Catalog", "db_name(}", 1},
- new object [] {"Indexes", "Owner", "@Owner", "user_name(}", 2},
+ new object [] {"Indexes", "Catalog", "@Catalog", "db_name()", 1},
+ new object [] {"Indexes", "Owner", "@Owner", "user_name()", 2},
new object [] {"Indexes", "Table", "@Table", "o.name", 3},
new object [] {"Indexes", "Name", "@Name", "x.name", 4},
public override DataTable GetSchema ()
{
+ if (state == ConnectionState.Closed)
+ throw ExceptionHelper.ConnectionClosed ();
+
return MetaDataCollections.Instance;
}
public override DataTable GetSchema (String collectionName, string [] restrictionValues)
{
- if (collectionName == null)
- //LAMESPEC: In MS.NET, if collectionName is null, it throws ArgumentException.
- throw new ArgumentException ();
+ // LAMESPEC: In MS.NET, if collectionName is null, it throws ArgumentException.
- String cName = null;
+ if (state == ConnectionState.Closed)
+ throw ExceptionHelper.ConnectionClosed ();
+
+ String cName = null;
DataTable schemaTable = MetaDataCollections.Instance;
int length = restrictionValues == null ? 0 : restrictionValues.Length;
cName = row["CollectionName"].ToString();
}
}
+
if (cName == null)
- throw new ArgumentException ("The requested collection ('" + collectionName + "') is not defined.");
+ throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
+ "The requested collection ({0}) is not defined.",
+ collectionName));
SqlCommand command = null;
DataTable dataTable = new DataTable ();
" where (name = @Name or (@Name is null))", this);
command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
break;
+ case "StructuredTypeMembers":
+ // Only available on SQL Server 2008
+ // Running it again SQL 2005 results in the following exception:
+ // Unable to build the 'StructuredTypeMembers' collection because
+ // execution of the SQL query failed. See the inner exception for details.
+ // ---> System.Data.SqlClient.SqlException: Invalid object name 'sys.table_types'.
+ //
+ // I don't have access to SQL Server 2008 right now,
+ // and can't find any online documentation on the 'sys.table_types'
+ // view
+ throw new NotImplementedException ();
case "Views":
command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, CHECK_OPTION, " +
"IS_UPDATABLE from INFORMATION_SCHEMA.VIEWS where (TABLE_CATALOG" +
case "MetaDataCollections":
return MetaDataCollections.Instance;
case "DataSourceInformation":
- throw new NotImplementedException ();
+ return DataSourceInformation.GetInstance (this);
case "DataTypes":
return DataTypes.Instance;
case "ReservedWords":
public static void ChangePassword (string connectionString, string newPassword)
{
- if (connectionString == null || newPassword == null || newPassword == String.Empty)
- throw new ArgumentNullException ();
+ if (String.IsNullOrEmpty (connectionString))
+ throw new ArgumentNullException ("The 'connectionString' cannot be null or empty.");
+ if (String.IsNullOrEmpty (newPassword))
+ throw new ArgumentNullException ("The 'newPassword' cannot be null or empty.");
if (newPassword.Length > 128)
- throw new ArgumentException ("The value of newPassword exceeds its permittable length which is 128");
+ throw new ArgumentException ("The length of 'newPassword' cannot exceed 128 characters.");
using (SqlConnection conn = new SqlConnection (connectionString)) {
conn.Open ();
conn.tds.Execute (String.Format ("sp_password '{0}', '{1}', '{2}'",
public static void ClearAllPools ()
{
- Hashtable pools = SqlConnection.sqlConnectionPools.GetConnectionPool ();
+ // FIXME: locking
+ IDictionary pools = SqlConnection.sqlConnectionPools.GetConnectionPool ();
foreach (TdsConnectionPool pool in pools.Values) {
- if (pool != null) {
+ if (pool != null)
pool.ResetConnectionPool ();
- ITds tds = pool.GetConnection ();
- tds.Pooling = false;
- }
}
+ pools.Clear ();
}
public static void ClearPool (SqlConnection connection)
{
+ if (connection == null)
+ throw new ArgumentNullException ("connection");
+
+ // FIXME: locking
if (connection.pooling) {
- connection.pooling = false;
- if (connection.pool != null)
- connection.pool.ResetConnectionPool (connection.Tds);
+ TdsConnectionPool pool = sqlConnectionPools.GetConnectionPool (connection.ConnectionString);
+ if (pool != null)
+ pool.ResetConnectionPool ();
}
}
#if NET_2_0
#region Fields Net 2
- bool async = false;
+ bool async;
+ bool userInstance;
#endregion // Fields Net 2