2 // System.Data.SqlClient.SqlConnection.cs
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Daniel Morgan (danmorg@sc.rr.com)
7 // Tim Coleman (tim@timcoleman.com)
8 // Phillip Jerkins (Phillip.Jerkins@morgankeegan.com)
9 // Diego Caravana (diego@toth.it)
11 // Copyright (C) Ximian, Inc 2002
12 // Copyright (C) Daniel Morgan 2002, 2003
13 // Copyright (C) Tim Coleman, 2002, 2003
14 // Copyright (C) Phillip Jerkins, 2003
18 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
20 // Permission is hereby granted, free of charge, to any person obtaining
21 // a copy of this software and associated documentation files (the
22 // "Software"), to deal in the Software without restriction, including
23 // without limitation the rights to use, copy, modify, merge, publish,
24 // distribute, sublicense, and/or sell copies of the Software, and to
25 // permit persons to whom the Software is furnished to do so, subject to
26 // the following conditions:
28 // The above copyright notice and this permission notice shall be
29 // included in all copies or substantial portions of the Software.
31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 using Mono.Data.Tds.Protocol;
43 using System.Collections;
44 using System.Collections.Specialized;
45 using System.ComponentModel;
47 using System.Data.Common;
48 using System.EnterpriseServices;
49 using System.Globalization;
51 using System.Net.Sockets;
55 namespace System.Data.SqlClient {
56 [DefaultEvent ("InfoMessage")]
58 public sealed class SqlConnection : DbConnection, IDbConnection, ICloneable
60 public sealed class SqlConnection : Component, IDbConnection, ICloneable
66 // The set of SQL connection pools
67 static TdsConnectionPoolManager sqlConnectionPools = new TdsConnectionPoolManager (TdsVersion.tds70);
69 const int DEFAULT_PACKETSIZE = 8000;
71 const int DEFAULT_PACKETSIZE = 8192;
73 const int DEFAULT_CONNECTIONTIMEOUT = 15;
74 const int DEFAULT_MAXPOOLSIZE = 100;
75 const int DEFAULT_MINPOOLSIZE = 0;
76 const int DEFAULT_PORT = 1433;
78 // The current connection pool
79 TdsConnectionPool pool;
81 // The connection string that identifies this connection
82 string connectionString;
84 // The transaction object for the current transaction
85 SqlTransaction transaction;
87 // Connection parameters
89 TdsConnectionParameters parms = new TdsConnectionParameters ();
90 NameValueCollection connStringParameters;
94 int connectionTimeout;
99 bool fireInfoMessageEventOnUserErrors;
100 bool statisticsEnabled;
103 ConnectionState state = ConnectionState.Closed;
105 SqlDataReader dataReader;
115 public SqlConnection ()
116 : this (String.Empty)
120 public SqlConnection (string connectionString)
122 Init (connectionString);
125 private void Init (string connectionString)
127 connectionTimeout = DEFAULT_CONNECTIONTIMEOUT;
128 dataSource = string.Empty;
129 packetSize = DEFAULT_PACKETSIZE;
131 ConnectionString = connectionString;
134 #endregion // Constructors
138 #if NET_1_0 || ONLY_1_1
139 [DataSysDescription ("Information used to connect to a DataSource, such as 'Data Source=x;Initial Catalog=x;Integrated Security=SSPI'.")]
142 [EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
143 [RecommendedAsConfigurable (true)]
144 [RefreshProperties (RefreshProperties.All)]
149 string ConnectionString {
151 if (connectionString == null)
153 return connectionString;
155 [MonoTODO("persist security info, encrypt, enlist keyword not implemented")]
157 if (state == ConnectionState.Open)
158 throw new InvalidOperationException ("Not Allowed to change ConnectionString property while Connection state is OPEN");
159 SetConnectionString (value);
164 [DataSysDescription ("Current connection timeout value, 'Connect Timeout=X' in the ConnectionString.")]
166 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
171 int ConnectionTimeout {
172 get { return connectionTimeout; }
176 [DataSysDescription ("Current SQL Server database, 'Initial Catalog=X' in the connection string.")]
178 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
185 if (State == ConnectionState.Open)
187 return parms.Database ;
191 internal SqlDataReader DataReader {
192 get { return dataReader; }
193 set { dataReader = value; }
197 [DataSysDescription ("Current SqlServer that the connection is opened to, 'Data Source=X' in the connection string. ")]
201 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
207 get { return dataSource; }
211 [DataSysDescription ("Network packet size, 'Packet Size=x' in the connection string.")]
213 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
214 public int PacketSize {
216 if (State == ConnectionState.Open)
217 return ((Tds) tds).PacketSize;
224 [DataSysDescription ("Version of the SQL Server accessed by the SqlConnection.")]
226 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
231 string ServerVersion {
233 if (state == ConnectionState.Closed)
234 throw ExceptionHelper.ConnectionClosed ();
236 return tds.ServerVersion;
242 [DataSysDescription ("The ConnectionState indicating whether the connection is open or closed.")]
244 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
249 ConnectionState State {
250 get { return state; }
257 internal SqlTransaction Transaction {
258 get { return transaction; }
259 set { transaction = value; }
263 [DataSysDescription ("Workstation Id, 'Workstation ID=x' in the connection string.")]
265 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
266 public string WorkstationId {
267 get { return parms.Hostname; }
270 internal XmlReader XmlReader {
271 get { return xmlReader; }
272 set { xmlReader = value; }
276 public bool FireInfoMessageEventOnUserErrors {
277 get { return fireInfoMessageEventOnUserErrors; }
278 set { fireInfoMessageEventOnUserErrors = value; }
281 [DefaultValue (false)]
282 public bool StatisticsEnabled {
283 get { return statisticsEnabled; }
284 set { statisticsEnabled = value; }
287 #endregion // Properties
292 [DataSysDescription ("Event triggered when messages arrive from the DataSource.")]
294 public event SqlInfoMessageEventHandler InfoMessage;
297 [DataSysDescription ("Event triggered when the connection changes state.")]
298 public new event StateChangeEventHandler StateChange;
305 private void ErrorHandler (object sender, TdsInternalErrorMessageEventArgs e)
307 throw new SqlException (e.Class, e.LineNumber, e.Message, e.Number, e.Procedure, e.Server, "Mono SqlClient Data Provider", e.State);
310 private void MessageHandler (object sender, TdsInternalInfoMessageEventArgs e)
312 OnSqlInfoMessage (CreateSqlInfoMessageEvent (e.Errors));
315 #endregion // Delegates
319 internal string GetConnStringKeyValue (params string [] keys)
321 if (connStringParameters == null || connStringParameters.Count == 0)
324 foreach (string key in keys) {
325 string value = connStringParameters [key];
333 public new SqlTransaction BeginTransaction ()
335 return BeginTransaction (IsolationLevel.ReadCommitted, String.Empty);
338 public new SqlTransaction BeginTransaction (IsolationLevel iso)
340 return BeginTransaction (iso, String.Empty);
343 public SqlTransaction BeginTransaction (string transactionName)
345 return BeginTransaction (IsolationLevel.ReadCommitted, transactionName);
348 public SqlTransaction BeginTransaction (IsolationLevel iso, string transactionName)
350 if (state == ConnectionState.Closed)
351 throw ExceptionHelper.ConnectionClosed ();
352 if (transaction != null)
353 throw new InvalidOperationException ("SqlConnection does not support parallel transactions.");
355 string isolevel = String.Empty;
357 case IsolationLevel.ReadUncommitted:
358 isolevel = "READ UNCOMMITTED";
360 case IsolationLevel.RepeatableRead:
361 isolevel = "REPEATABLE READ";
363 case IsolationLevel.Serializable:
364 isolevel = "SERIALIZABLE";
366 case IsolationLevel.ReadCommitted:
367 isolevel = "READ COMMITTED";
370 case IsolationLevel.Snapshot:
371 isolevel = "SNAPSHOT";
373 case IsolationLevel.Unspecified:
374 iso = IsolationLevel.ReadCommitted;
375 isolevel = "READ COMMITTED";
377 case IsolationLevel.Chaos:
378 throw new ArgumentOutOfRangeException ("IsolationLevel",
379 string.Format (CultureInfo.CurrentCulture,
380 "The IsolationLevel enumeration " +
381 "value, {0}, is not supported by " +
382 "the .Net Framework SqlClient " +
383 "Data Provider.", (int) iso));
387 throw new ArgumentOutOfRangeException ("IsolationLevel",
388 string.Format (CultureInfo.CurrentCulture,
389 "The IsolationLevel enumeration value, {0}, is invalid.",
392 throw new ArgumentException ("Invalid IsolationLevel parameter: must be ReadCommitted, ReadUncommitted, RepeatableRead, or Serializable.");
396 tds.Execute (String.Format ("SET TRANSACTION ISOLATION LEVEL {0};BEGIN TRANSACTION {1}", isolevel, transactionName));
398 transaction = new SqlTransaction (this, iso);
406 void ChangeDatabase (string database)
408 if (!IsValidDatabaseName (database))
409 throw new ArgumentException (String.Format ("The database name {0} is not valid.", database));
410 if (state != ConnectionState.Open)
411 throw new InvalidOperationException ("The connection is not open.");
412 tds.Execute (String.Format ("use [{0}]", database));
415 private void ChangeState (ConnectionState currentState)
417 ConnectionState originalState = state;
418 state = currentState;
419 OnStateChange (CreateStateChangeEvent (originalState, currentState));
428 if (transaction != null && transaction.IsOpen)
429 transaction.Rollback ();
431 if (dataReader != null || xmlReader != null) {
432 if(tds != null) tds.SkipToEnd ();
437 if (tds != null && tds.IsConnected) {
438 if (pooling && tds.Pooling) {
440 if(pool != null) pool.ReleaseConnection (ref tds);
442 if(pool != null) pool.ReleaseConnection (tds);
445 if(tds != null) tds.Disconnect ();
449 tds.TdsErrorMessage -= new TdsInternalErrorMessageEventHandler (ErrorHandler);
450 tds.TdsInfoMessage -= new TdsInternalInfoMessageEventHandler (MessageHandler);
453 ChangeState (ConnectionState.Closed);
456 public new SqlCommand CreateCommand ()
458 SqlCommand command = new SqlCommand ();
459 command.Connection = this;
463 private SqlInfoMessageEventArgs CreateSqlInfoMessageEvent (TdsInternalErrorCollection errors)
465 return new SqlInfoMessageEventArgs (errors);
468 private StateChangeEventArgs CreateStateChangeEvent (ConnectionState originalState, ConnectionState currentState)
470 return new StateChangeEventArgs (originalState, currentState);
473 protected override void Dispose (bool disposing)
480 if (State == ConnectionState.Open)
482 ConnectionString = string.Empty;
483 SetDefaultConnectionParameters (this.connStringParameters);
487 base.Dispose (disposing);
491 [MonoTODO ("Not sure what this means at present.")]
492 public void EnlistDistributedTransaction (ITransaction transaction)
494 throw new NotImplementedException ();
497 object ICloneable.Clone ()
499 return new SqlConnection (ConnectionString);
503 protected override DbTransaction BeginDbTransaction (IsolationLevel level)
505 return (DbTransaction)BeginTransaction (level);
508 protected override DbCommand CreateDbCommand ()
510 return CreateCommand ();
513 IDbTransaction IDbConnection.BeginTransaction ()
515 return BeginTransaction ();
518 IDbTransaction IDbConnection.BeginTransaction (IsolationLevel iso)
520 return BeginTransaction (iso);
523 IDbCommand IDbConnection.CreateCommand ()
525 return CreateCommand ();
535 string serverName = string.Empty;
536 if (state == ConnectionState.Open)
537 throw new InvalidOperationException ("The Connection is already Open (State=Open)");
539 if (connectionString == null || connectionString.Trim().Length == 0)
540 throw new InvalidOperationException ("Connection string has not been initialized.");
544 if(!ParseDataSource (dataSource, out port, out serverName))
545 throw new SqlException(20, 0, "SQL Server does not exist or access denied.", 17, "ConnectionOpen (Connect()).", dataSource, parms.ApplicationName, 0);
546 tds = new Tds70 (serverName, port, PacketSize, ConnectionTimeout);
549 if(!ParseDataSource (dataSource, out port, out serverName))
550 throw new SqlException(20, 0, "SQL Server does not exist or access denied.", 17, "ConnectionOpen (Connect()).", dataSource, parms.ApplicationName, 0);
552 TdsConnectionInfo info = new TdsConnectionInfo (serverName, port, packetSize, ConnectionTimeout, minPoolSize, maxPoolSize);
553 pool = sqlConnectionPools.GetConnectionPool (connectionString, info);
554 tds = pool.GetConnection ();
556 } catch (TdsTimeoutException e) {
557 throw SqlException.FromTdsInternalException ((TdsInternalException) e);
558 } catch (TdsInternalException e) {
559 throw SqlException.FromTdsInternalException (e);
562 tds.TdsErrorMessage += new TdsInternalErrorMessageEventHandler (ErrorHandler);
563 tds.TdsInfoMessage += new TdsInternalInfoMessageEventHandler (MessageHandler);
565 if (!tds.IsConnected) {
570 pool.ReleaseConnection (tds);
573 } else if (connectionReset) {
577 disposed = false; // reset this, so using () would call Close ().
578 ChangeState (ConnectionState.Open);
581 private bool ParseDataSource (string theDataSource, out int thePort, out string theServerName)
583 theServerName = string.Empty;
584 string theInstanceName = string.Empty;
586 if (theDataSource == null)
587 throw new ArgumentException("Format of initialization string does not conform to specifications");
589 thePort = DEFAULT_PORT; // default TCP port for SQL Server
593 if ((idx = theDataSource.IndexOf (",")) > -1) {
594 theServerName = theDataSource.Substring (0, idx);
595 string p = theDataSource.Substring (idx + 1);
596 thePort = Int32.Parse (p);
597 } else if ((idx = theDataSource.IndexOf ("\\")) > -1) {
598 theServerName = theDataSource.Substring (0, idx);
599 theInstanceName = theDataSource.Substring (idx + 1);
600 // do port discovery via UDP port 1434
601 port = DiscoverTcpPortViaSqlMonitor (theServerName, theInstanceName);
604 } else if (theDataSource.Length == 0 || theDataSource == "(local)")
605 theServerName = "localhost";
607 theServerName = theDataSource;
609 if ((idx = theServerName.IndexOf ("tcp:")) > -1)
610 theServerName = theServerName.Substring (idx + 4);
615 private bool ConvertIntegratedSecurity (string value)
617 if (value.ToUpper() == "SSPI")
620 return ConvertToBoolean("integrated security", value);
623 private bool ConvertToBoolean (string key, string value)
625 string upperValue = value.ToUpper ();
627 if (upperValue == "TRUE" || upperValue == "YES")
629 else if (upperValue == "FALSE" || upperValue == "NO")
632 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
633 "Invalid value \"{0}\" for key '{1}'.", value, key));
636 private int ConvertToInt32 (string key, string value)
639 return int.Parse (value);
640 } catch (Exception ex) {
641 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
642 "Invalid value \"{0}\" for key '{1}'.", value, key));
646 private int DiscoverTcpPortViaSqlMonitor (string ServerName, string InstanceName)
648 SqlMonitorSocket msock;
649 msock = new SqlMonitorSocket (ServerName, InstanceName);
650 int SqlServerPort = msock.DiscoverTcpPort (ConnectionTimeout);
652 return SqlServerPort;
655 void SetConnectionString (string connectionString)
657 NameValueCollection parameters = new NameValueCollection ();
658 SetDefaultConnectionParameters (parameters);
660 if ((connectionString == null) || (connectionString.Trim().Length == 0)) {
661 this.connectionString = connectionString;
662 this.connStringParameters = parameters;
666 connectionString += ";";
668 bool inQuote = false;
669 bool inDQuote = false;
672 string name = String.Empty;
673 string value = String.Empty;
674 StringBuilder sb = new StringBuilder ();
676 for (int i = 0; i < connectionString.Length; i += 1) {
677 char c = connectionString [i];
679 if (i == connectionString.Length - 1)
682 peek = connectionString [i + 1];
688 else if (peek.Equals (c)) {
698 else if (peek.Equals (c)) {
703 inDQuote = !inDQuote;
706 if (inDQuote || inQuote)
709 if (name != String.Empty && name != null) {
710 value = sb.ToString ();
711 SetProperties (name.ToUpper ().Trim() , value);
712 parameters [name.ToUpper ().Trim ()] = value.Trim ();
714 else if (sb.Length != 0)
715 throw new ArgumentException ("Format of initialization string does not conform to specifications");
718 value = String.Empty;
719 sb = new StringBuilder ();
723 if (inDQuote || inQuote || !inName)
725 else if (peek.Equals (c)) {
731 name = sb.ToString ();
732 sb = new StringBuilder ();
737 if (inQuote || inDQuote)
739 else if (sb.Length > 0 && !peek.Equals (';'))
748 connectionString = connectionString.Substring (0 , connectionString.Length-1);
749 this.connectionString = connectionString;
750 this.connStringParameters = parameters;
753 void SetDefaultConnectionParameters (NameValueCollection parameters)
756 dataSource = string.Empty;
757 connectionTimeout = DEFAULT_CONNECTIONTIMEOUT;
758 connectionReset = true;
760 maxPoolSize = DEFAULT_MAXPOOLSIZE;
761 minPoolSize = DEFAULT_MINPOOLSIZE;
762 packetSize = DEFAULT_PACKETSIZE;
764 parameters["APPLICATION NAME"] = "Mono SqlClient Data Provider";
765 parameters["CONNECT TIMEOUT"] = connectionTimeout.ToString (CultureInfo.InvariantCulture);
766 parameters["CONNECTION LIFETIME"] = "0";
767 parameters["CONNECTION RESET"] = "true";
768 parameters["ENLIST"] = "true";
769 parameters["INTEGRATED SECURITY"] = "false";
770 parameters["INITIAL CATALOG"] = string.Empty;
771 parameters["MAX POOL SIZE"] = maxPoolSize.ToString (CultureInfo.InvariantCulture);
772 parameters["MIN POOL SIZE"] = minPoolSize.ToString (CultureInfo.InvariantCulture);
773 parameters["NETWORK LIBRARY"] = "dbmssocn";
774 parameters["PACKET SIZE"] = packetSize.ToString (CultureInfo.InvariantCulture);
775 parameters["PERSIST SECURITY INFO"] = "false";
776 parameters["POOLING"] = "true";
777 parameters["WORKSTATION ID"] = Environment.MachineName;
780 parameters ["ASYNCHRONOUS PROCESSING"] = "false";
784 private void SetProperties (string name , string value)
788 case "APPLICATION NAME" :
789 parms.ApplicationName = value;
791 case "ATTACHDBFILENAME" :
792 case "EXTENDED PROPERTIES" :
793 case "INITIAL FILE NAME" :
794 parms.AttachDBFileName = value;
797 case "CONNECT TIMEOUT" :
798 case "CONNECTION TIMEOUT" :
799 int tmpTimeout = ConvertToInt32 ("connection timeout", value);
801 throw new ArgumentException ("Invalid CONNECTION TIMEOUT .. Must be an integer >=0 ");
803 connectionTimeout = tmpTimeout;
805 case "CONNECTION LIFETIME" :
807 case "CONNECTION RESET" :
808 connectionReset = ConvertToBoolean ("connection reset", value);
811 case "CURRENT LANGUAGE" :
812 parms.Language = value;
818 case "NETWORK ADDRESS" :
822 if (ConvertToBoolean("encrypt", value))
823 throw new NotImplementedException("SSL encryption for"
824 + " data sent between client and server is not"
828 if (!ConvertToBoolean("enlist", value))
829 throw new NotImplementedException("Disabling the automatic"
830 + " enlistment of connections in the thread's current"
831 + " transaction context is not implemented.");
833 case "INITIAL CATALOG" :
835 parms.Database = value;
837 case "INTEGRATED SECURITY" :
838 case "TRUSTED_CONNECTION" :
839 parms.DomainLogin = ConvertIntegratedSecurity(value);
841 case "MAX POOL SIZE" :
842 int tmpMaxPoolSize = ConvertToInt32 ("max pool size" , value);
843 if (tmpMaxPoolSize < 0)
844 throw new ArgumentException ("Invalid MAX POOL SIZE. Must be a intger >= 0");
846 maxPoolSize = tmpMaxPoolSize;
848 case "MIN POOL SIZE" :
849 int tmpMinPoolSize = ConvertToInt32 ("min pool size" , value);
850 if (tmpMinPoolSize < 0)
851 throw new ArgumentException ("Invalid MIN POOL SIZE. Must be a intger >= 0");
853 minPoolSize = tmpMinPoolSize;
856 case "MULTIPLEACTIVERESULTSETS":
858 case "ASYNCHRONOUS PROCESSING" :
860 async = ConvertToBoolean (name, value);
865 case "NETWORK LIBRARY" :
866 if (!value.ToUpper ().Equals ("DBMSSOCN"))
867 throw new ArgumentException ("Unsupported network library.");
870 int tmpPacketSize = ConvertToInt32 ("packet size", value);
871 if (tmpPacketSize < 512 || tmpPacketSize > 32767)
872 throw new ArgumentException ("Invalid PACKET SIZE. The integer must be between 512 and 32767");
874 packetSize = tmpPacketSize;
878 parms.Password = value;
880 case "PERSISTSECURITYINFO" :
881 case "PERSIST SECURITY INFO" :
882 // FIXME : not implemented
883 // throw new NotImplementedException ();
886 pooling = ConvertToBoolean("pooling", value);
894 case "WORKSTATION ID" :
895 parms.Hostname = value;
898 throw new ArgumentException("Keyword not supported :"+name);
902 static bool IsValidDatabaseName (string database)
904 if ( database == null || database.Trim().Length == 0 || database.Length > 128)
907 if (database[0] == '"' && database[database.Length] == '"')
908 database = database.Substring (1, database.Length - 2);
909 else if (Char.IsDigit (database[0]))
912 if (database[0] == '_')
915 foreach (char c in database.Substring (1, database.Length - 1))
916 if (!Char.IsLetterOrDigit (c) && c != '_' && c != '-')
921 private void OnSqlInfoMessage (SqlInfoMessageEventArgs value)
923 if (InfoMessage != null)
924 InfoMessage (this, value);
928 private new void OnStateChange (StateChangeEventArgs value)
930 if (StateChange != null)
931 StateChange (this, value);
935 private sealed class SqlMonitorSocket : UdpClient
937 // UDP port that the SQL Monitor listens
938 private static readonly int SqlMonitorUdpPort = 1434;
939 //private static readonly string SqlServerNotExist = "SQL Server does not exist or access denied";
941 private string server;
942 private string instance;
944 internal SqlMonitorSocket (string ServerName, string InstanceName)
945 : base (ServerName, SqlMonitorUdpPort)
948 instance = InstanceName;
951 internal int DiscoverTcpPort (int timeoutSeconds)
953 int SqlServerTcpPort;
954 Client.Blocking = false;
955 // send command to UDP 1434 (SQL Monitor) to get
956 // the TCP port to connect to the MS SQL server
957 ASCIIEncoding enc = new ASCIIEncoding ();
958 Byte[] rawrq = new Byte [instance.Length + 1];
960 enc.GetBytes (instance, 0, instance.Length, rawrq, 1);
961 int bytes = Send (rawrq, rawrq.Length);
967 long timeout = timeoutSeconds * 1000000;
968 result = Client.Poll ((int)timeout, SelectMode.SelectRead);
972 if (Client.Available <= 0)
975 IPEndPoint endpoint = new IPEndPoint (Dns.GetHostEntry ("localhost").AddressList [0], 0);
977 IPEndPoint endpoint = new IPEndPoint (Dns.GetHostByName ("localhost").AddressList [0], 0);
981 rawrs = Receive (ref endpoint);
983 string rs = Encoding.ASCII.GetString (rawrs);
985 string[] rawtokens = rs.Split (';');
986 Hashtable data = new Hashtable ();
987 for (int i = 0; i < rawtokens.Length / 2 && i < 256; i++) {
988 data [rawtokens [i * 2]] = rawtokens [ i * 2 + 1];
990 if (!data.ContainsKey ("tcp"))
991 throw new NotImplementedException ("Only TCP/IP is supported.");
993 SqlServerTcpPort = int.Parse ((string) data ["tcp"]);
996 return SqlServerTcpPort;
1004 public ColumnInfo (string name, Type type)
1006 this.name = name; this.type = type;
1010 static class ReservedWords
1012 static readonly string [] reservedWords =
1014 "ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER",
1015 "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY",
1016 "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE",
1017 "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC",
1018 "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ",
1019 "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE",
1020 "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK",
1021 "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE",
1022 "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN",
1023 "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT",
1024 "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY",
1025 "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL",
1026 "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE",
1027 "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT",
1028 "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT",
1029 "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE",
1030 "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE",
1031 "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER",
1032 "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT",
1033 "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN",
1034 "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD",
1035 "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK",
1036 "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER",
1037 "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL",
1038 "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF",
1039 "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS",
1040 "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN",
1041 "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE",
1042 "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW",
1043 "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN",
1044 "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL",
1045 "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT", "ABSOLUTE",
1046 "FOUND", "PRESERVE", "ACTION", "FREE", "PRIOR", "ADMIN",
1047 "GENERAL", "PRIVILEGES", "AFTER", "GET", "READS",
1048 "AGGREGATE", "GLOBAL", "REAL", "ALIAS", "GO", "RECURSIVE",
1049 "ALLOCATE", "GROUPING", "REF", "ARE", "HOST", "REFERENCING",
1050 "ARRAY", "HOUR", "RELATIVE", "ASSERTION", "IGNORE", "RESULT",
1051 "AT", "IMMEDIATE", "RETURNS", "BEFORE", "INDICATOR", "ROLE",
1052 "BINARY", "INITIALIZE", "ROLLUP", "BIT", "INITIALLY",
1053 "ROUTINE", "BLOB", "INOUT", "ROW", "BOOLEAN", "INPUT",
1054 "ROWS", "BOTH", "INT", "SAVEPOINT", "BREADTH", "INTEGER",
1055 "SCROLL", "CALL", "INTERVAL", "SCOPE", "CASCADED",
1056 "ISOLATION", "SEARCH", "CAST", "ITERATE", "SECOND",
1057 "CATALOG", "LANGUAGE", "SECTION", "CHAR", "LARGE",
1058 "SEQUENCE", "CHARACTER", "LAST", "SESSION", "CLASS",
1059 "LATERAL", "SETS", "CLOB", "LEADING", "SIZE", "COLLATION",
1060 "LESS", "SMALLINT", "COMPLETION", "LEVEL", "SPACE",
1061 "CONNECT", "LIMIT", "SPECIFIC", "CONNECTION", "LOCAL",
1062 "SPECIFICTYPE", "CONSTRAINTS", "LOCALTIME", "SQL",
1063 "CONSTRUCTOR", "LOCALTIMESTAMP", "SQLEXCEPTION",
1064 "CORRESPONDING", "LOCATOR", "SQLSTATE", "CUBE", "MAP",
1065 "SQLWARNING", "CURRENT_PATH", "MATCH", "START",
1066 "CURRENT_ROLE", "MINUTE", "STATE", "CYCLE", "MODIFIES",
1067 "STATEMENT", "DATA", "MODIFY", "STATIC", "DATE", "MODULE",
1068 "STRUCTURE", "DAY", "MONTH", "TEMPORARY", "DEC", "NAMES",
1069 "TERMINATE", "DECIMAL", "NATURAL", "THAN", "DEFERRABLE",
1070 "NCHAR", "TIME", "DEFERRED", "NCLOB", "TIMESTAMP", "DEPTH",
1071 "NEW", "TIMEZONE_HOUR", "DEREF", "NEXT", "TIMEZONE_MINUTE",
1072 "DESCRIBE", "NO", "TRAILING", "DESCRIPTOR", "NONE",
1073 "TRANSLATION", "DESTROY", "NUMERIC", "TREAT", "DESTRUCTOR",
1074 "OBJECT", "TRUE", "DETERMINISTIC", "OLD", "UNDER",
1075 "DICTIONARY", "ONLY", "UNKNOWN", "DIAGNOSTICS", "OPERATION",
1076 "UNNEST", "DISCONNECT", "ORDINALITY", "USAGE", "DOMAIN",
1077 "OUT", "USING", "DYNAMIC", "OUTPUT", "VALUE", "EACH",
1078 "PAD", "VARCHAR", "END-EXEC", "PARAMETER", "VARIABLE",
1079 "EQUALS", "PARAMETERS", "WHENEVER", "EVERY", "PARTIAL",
1080 "WITHOUT", "EXCEPTION", "PATH", "WORK", "EXTERNAL",
1081 "POSTFIX", "WRITE", "FALSE", "PREFIX", "YEAR", "FIRST",
1082 "PREORDER", "ZONE", "FLOAT", "PREPARE", "ADA", "AVG",
1083 "BIT_LENGTH", "CHAR_LENGTH", "CHARACTER_LENGTH", "COUNT",
1084 "EXTRACT", "FORTRAN", "INCLUDE", "INSENSITIVE", "LOWER",
1085 "MAX", "MIN", "OCTET_LENGTH", "OVERLAPS", "PASCAL",
1086 "POSITION", "SQLCA", "SQLCODE", "SQLERROR", "SUBSTRING",
1087 "SUM", "TRANSLATE", "TRIM", "UPPER"
1089 static DataTable instance;
1090 static public DataTable Instance {
1092 if (instance == null) {
1094 instance = new DataTable ("ReservedWords");
1095 instance.Columns.Add ("ReservedWord", typeof(string));
1096 foreach (string reservedWord in reservedWords)
1098 row = instance.NewRow();
1100 row["ReservedWord"] = reservedWord;
1101 instance.Rows.Add(row);
1109 static class MetaDataCollections
1111 static readonly ColumnInfo [] columns = {
1112 new ColumnInfo ("CollectionName", typeof (string)),
1113 new ColumnInfo ("NumberOfRestrictions", typeof (int)),
1114 new ColumnInfo ("NumberOfIdentifierParts", typeof (int))
1117 static readonly object [][] rows = {
1118 new object [] {"MetaDataCollections", 0, 0},
1119 new object [] {"DataSourceInformation", 0, 0},
1120 new object [] {"DataTypes", 0, 0},
1121 new object [] {"Restrictions", 0, 0},
1122 new object [] {"ReservedWords", 0, 0},
1123 new object [] {"Users", 1, 1},
1124 new object [] {"Databases", 1, 1},
1125 new object [] {"Tables", 4, 3},
1126 new object [] {"Columns", 4, 4},
1127 new object [] {"StructuredTypeMembers", 4, 4},
1128 new object [] {"Views", 3, 3},
1129 new object [] {"ViewColumns", 4, 4},
1130 new object [] {"ProcedureParameters", 4, 1},
1131 new object [] {"Procedures", 4, 3},
1132 new object [] {"ForeignKeys", 4, 3},
1133 new object [] {"IndexColumns", 5, 4},
1134 new object [] {"Indexes", 4, 3},
1135 new object [] {"UserDefinedTypes", 2, 1}
1138 static DataTable instance;
1139 static public DataTable Instance {
1141 if (instance == null) {
1142 instance = new DataTable ("MetaDataCollections");
1143 foreach (ColumnInfo c in columns)
1144 instance.Columns.Add (c.name, c.type);
1145 foreach (object [] row in rows)
1146 instance.LoadDataRow (row, true);
1153 static class DataSourceInformation
1155 static readonly ColumnInfo [] columns = {
1156 new ColumnInfo ("CompositeIdentifierSeparatorPattern", typeof (string)),
1157 new ColumnInfo ("DataSourceProductName", typeof(string)),
1158 new ColumnInfo ("DataSourceProductVersion", typeof(string)),
1159 new ColumnInfo ("DataSourceProductVersionNormalized", typeof(string)),
1160 new ColumnInfo ("GroupByBehavior", typeof(GroupByBehavior)),
1161 new ColumnInfo ("IdentifierPattern", typeof(string)),
1162 new ColumnInfo ("IdentifierCase", typeof(IdentifierCase)),
1163 new ColumnInfo ("OrderByColumnsInSelect", typeof(bool)),
1164 new ColumnInfo ("ParameterMarkerFormat", typeof(string)),
1165 new ColumnInfo ("ParameterMarkerPattern", typeof(string)),
1166 new ColumnInfo ("ParameterNameMaxLength", typeof(int)),
1167 new ColumnInfo ("ParameterNamePattern", typeof(string)),
1168 new ColumnInfo ("QuotedIdentifierPattern", typeof(string)),
1169 new ColumnInfo ("QuotedIdentifierCase", typeof(IdentifierCase)),
1170 new ColumnInfo ("StatementSeparatorPattern", typeof(string)),
1171 new ColumnInfo ("StringLiteralPattern", typeof(string)),
1172 new ColumnInfo ("SupportedJoinOperators", typeof(SupportedJoinOperators))
1175 static public DataTable GetInstance (SqlConnection conn)
1177 DataTable table = new DataTable ("DataSourceInformation");
1178 foreach (ColumnInfo c in columns)
1179 table.Columns.Add (c.name, c.type);
1180 DataRow row = table.NewRow ();
1182 row [1] = "Microsoft SQL Server";
1183 row [2] = conn.ServerVersion;;
1184 row [3] = conn.ServerVersion;;
1185 row [4] = GroupByBehavior.Unrelated;
1186 row [5] = @"(^\[\p{Lo}\p{Lu}\p{Ll}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Nd}@$#_]*$)|(^\[[^\]\0]|\]\]+\]$)|(^\""[^\""\0]|\""\""+\""$)";
1187 row [6] = IdentifierCase.Insensitive; // FIXME: obtain this from SQL Server
1190 row [9] = @"@[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)";
1192 row [11] = @"^[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)";
1193 row [12] = @"(([^\[]|\]\])*)";
1194 row [13] = IdentifierCase.Insensitive; // FIXME: obtain this from SQL Server
1196 row [15] = "'(([^']|'')*)'";
1197 row [16] = (SupportedJoinOperators.FullOuter | SupportedJoinOperators.Inner |
1198 SupportedJoinOperators.LeftOuter | SupportedJoinOperators.RightOuter);
1199 table.Rows.Add (row);
1204 static class DataTypes
1206 static readonly ColumnInfo [] columns = {
1207 new ColumnInfo ("TypeName", typeof(string)),
1208 new ColumnInfo ("ProviderDbType", typeof(int)),
1209 new ColumnInfo ("ColumnSize", typeof(long)),
1210 new ColumnInfo ("CreateFormat", typeof(string)),
1211 new ColumnInfo ("CreateParameters", typeof(string)),
1212 new ColumnInfo ("DataType", typeof(string)),
1213 new ColumnInfo ("IsAutoIncrementable", typeof(bool)),
1214 new ColumnInfo ("IsBestMatch", typeof(bool)),
1215 new ColumnInfo ("IsCaseSensitive", typeof(bool)),
1216 new ColumnInfo ("IsFixedLength", typeof(bool)),
1217 new ColumnInfo ("IsFixedPrecisionScale", typeof(bool)),
1218 new ColumnInfo ("IsLong", typeof(bool)),
1219 new ColumnInfo ("IsNullable", typeof(bool)),
1220 new ColumnInfo ("IsSearchable", typeof(bool)),
1221 new ColumnInfo ("IsSearchableWithLike", typeof(bool)),
1222 new ColumnInfo ("IsUnsigned", typeof(bool)),
1223 new ColumnInfo ("MaximumScale", typeof(short)),
1224 new ColumnInfo ("MinimumScale", typeof(short)),
1225 new ColumnInfo ("IsConcurrencyType", typeof(bool)),
1226 new ColumnInfo ("IsLiteralSupported", typeof(bool)),
1227 new ColumnInfo ("LiteralPrefix", typeof(string)),
1228 new ColumnInfo ("LiteralSuffix", typeof(string))
1231 static readonly object [][] rows = {
1232 new object [] {"smallint", 16, 5, "smallint", null, "System.Int16", true, true,
1233 false, true, true, false, true, true, false, false, null,
1234 null, false, null, null, null},
1235 new object [] {"int", 8, 10, "int", null, "System.Int32",
1236 true, true, false, true, true, false, true, true, false,
1237 false, null, null, false, null, null, null},
1238 new object [] {"real", 13, 7, "real", null,
1239 "System.Single", false, true, false, true, false, false,
1240 true, true, false, false, null, null, false, null, null, null},
1241 new object [] {"float", 6, 53, "float({0})",
1242 "number of bits used to store the mantissa", "System.Double",
1243 false, true, false, true, false, false, true, true,
1244 false, false, null, null, false, null, null, null},
1245 new object [] {"money", 9, 19, "money", null,
1246 "System.Decimal", false, false, false, true, true,
1247 false, true, true, false, false, null, null, false,
1249 new object [] {"smallmoney", 17, 10, "smallmoney", null,
1250 "System.Decimal", false, false, false, true, true, false,
1251 true, true, false, false, null, null, false, null, null, null},
1252 new object [] {"bit", 2, 1, "bit", null, "System.Boolean",
1253 false, false, false, true, false, false, true, true,
1254 false, null, null, null, false, null, null, null},
1255 new object [] {"tinyint", 20, 3, "tinyint", null,
1256 "System.SByte", true, true, false, true, true, false,
1257 true, true, false, true, null, null, false, null, null, null},
1258 new object [] {"bigint", 0, 19, "bigint", null,
1259 "System.Int64", true, true, false, true, true, false,
1260 true, true, false, false, null, null, false, null, null, null},
1261 new object [] {"timestamp", 19, 8, "timestamp", null,
1262 "System.Byte[]", false, false, false, true, false, false,
1263 false, true, false, null, null, null, true, null, "0x", null},
1264 new object [] {"binary", 1, 8000, "binary({0})", "length",
1265 "System.Byte[]", false, true, false, true, false, false,
1266 true, true, false, null, null, null, false, null, "0x", null},
1267 new object [] {"image", 7, 2147483647, "image", null,
1268 "System.Byte[]", false, true, false, false, false, true,
1269 true, false, false, null, null, null, false, null, "0x", null},
1270 new object [] {"text", 18, 2147483647, "text", null,
1271 "System.String", false, true, false, false, false, true,
1272 true, false, true, null, null, null, false, null, "'", "'"},
1273 new object [] {"ntext", 11, 1073741823, "ntext", null,
1274 "System.String", false, true, false, false, false, true,
1275 true, false, true, null, null, null, false, null, "N'", "'"},
1276 new object [] {"decimal", 5, 38, "decimal({0}, {1})",
1277 "precision,scale", "System.Decimal", true, true, false,
1278 true, false, false, true, true, false, false, 38, 0,
1279 false, null, null, null},
1280 new object [] {"numeric", 5, 38, "numeric({0}, {1})",
1281 "precision,scale", "System.Decimal", true, true, false,
1282 true, false, false, true, true, false, false, 38, 0,
1283 false, null, null, null},
1284 new object [] {"datetime", 4, 23, "datetime", null,
1285 "System.DateTime", false, true, false, true, false, false,
1286 true, true, true, null, null, null, false, null, "{ts '", "'}"},
1287 new object [] {"smalldatetime", 15, 16, "smalldatetime", null,
1288 "System.DateTime", false, true, false, true, false, false,
1289 true, true, true, null, null, null, false, null, "{ts '", "'}"},
1290 new object [] {"sql_variant", 23, null, "sql_variant",
1291 null, "System.Object", false, true, false, false, false,
1292 false, true, true, false, null, null, null, false, false,
1294 new object [] {"xml", 25, 2147483647, "xml", null,
1295 "System.String", false, false, false, false, false, true,
1296 true, false, false, null, null, null, false, false, null, null},
1297 new object [] {"varchar", 22, 2147483647, "varchar({0})",
1298 "max length", "System.String", false, true, false, false,
1299 false, false, true, true, true, null, null, null, false,
1301 new object [] {"char", 3, 2147483647, "char({0})", "length",
1302 "System.String", false, true, false, true, false, false,
1303 true, true, true, null, null, null, false, null, "'", "'"},
1304 new object [] {"nchar", 10, 1073741823, "nchar({0})", "length",
1305 "System.String", false, true, false, true, false, false,
1306 true, true, true, null, null, null, false, null, "N'", "'"},
1307 new object [] {"nvarchar", 12, 1073741823, "nvarchar({0})", "max length",
1308 "System.String", false, true, false, false, false, false, true, true,
1309 true, null, null, null, false, null, "N'", "'"},
1310 new object [] {"varbinary", 21, 1073741823, "varbinary({0})",
1311 "max length", "System.Byte[]", false, true, false, false,
1312 false, false, true, true, false, null, null, null, false,
1314 new object [] {"uniqueidentifier", 14, 16, "uniqueidentifier", null,
1315 "System.Guid", false, true, false, true, false, false, true,
1316 true, false, null, null, null, false, null, "'", "'"},
1317 new object [] {"date", 31, 3L, "date", DBNull.Value,
1318 "System.DateTime", false, false, false, true, true, false,
1319 true, true, true, DBNull.Value, DBNull.Value, DBNull.Value,
1320 false, DBNull.Value, "{ts '", "'}"},
1321 new object [] {"time", 32, 5L, "time({0})", "scale",
1322 "System.TimeSpan", false, false, false, false, false, false,
1323 true, true, true, DBNull.Value, (short) 7, (short) 0,
1324 false, DBNull.Value, "{ts '", "'}"},
1325 new object [] {"datetime2", 33, 8L, "datetime2({0})", "scale",
1326 "System.DateTime", false, true, false, false, false, false,
1327 true, true, true, DBNull.Value, (short) 7, (short) 0,
1328 false, DBNull.Value, "{ts '", "'}"},
1329 new object [] {"datetimeoffset", 34, 10L, "datetimeoffset({0})",
1330 "scale", "System.DateTimeOffset", false, true, false, false,
1331 false, false, true, true, true, DBNull.Value, (short) 7, (short) 0,
1332 false, DBNull.Value, "{ts '", "'}"}
1335 static DataTable instance;
1336 static public DataTable Instance {
1338 if (instance == null) {
1339 instance = new DataTable ("DataTypes");
1340 foreach (ColumnInfo c in columns)
1341 instance.Columns.Add (c.name, c.type);
1342 foreach (object [] row in rows)
1343 instance.LoadDataRow (row, true);
1350 static class Restrictions
1352 static readonly ColumnInfo [] columns = {
1353 new ColumnInfo ("CollectionName", typeof (string)),
1354 new ColumnInfo ("RestrictionName", typeof(string)),
1355 new ColumnInfo ("ParameterName", typeof(string)),
1356 new ColumnInfo ("RestrictionDefault", typeof(string)),
1357 new ColumnInfo ("RestrictionNumber", typeof(int))
1360 static readonly object [][] rows = {
1361 new object [] {"Users", "User_Name", "@Name", "name", 1},
1362 new object [] {"Databases", "Name", "@Name", "Name", 1},
1364 new object [] {"Tables", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
1365 new object [] {"Tables", "Owner", "@Owner", "TABLE_SCHEMA", 2},
1366 new object [] {"Tables", "Table", "@Name", "TABLE_NAME", 3},
1367 new object [] {"Tables", "TableType", "@TableType", "TABLE_TYPE", 4},
1369 new object [] {"Columns", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
1370 new object [] {"Columns", "Owner", "@Owner", "TABLE_SCHEMA", 2},
1371 new object [] {"Columns", "Table", "@Table", "TABLE_NAME", 3},
1372 new object [] {"Columns", "Column", "@Column", "COLUMN_NAME", 4},
1374 new object [] {"StructuredTypeMembers", "Catalog", "@Catalog", "TYPE_CATALOG", 1},
1375 new object [] {"StructuredTypeMembers", "Owner", "@Owner", "TYPE_SCHEMA", 2},
1376 new object [] {"StructuredTypeMembers", "Type", "@Type", "TYPE_NAME", 3},
1377 new object [] {"StructuredTypeMembers", "Member", "@Member", "MEMBER_NAME", 4},
1379 new object [] {"Views", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
1380 new object [] {"Views", "Owner", "@Owner", "TABLE_SCHEMA", 2},
1381 new object [] {"Views", "Table", "@Table", "TABLE_NAME", 3},
1383 new object [] {"ViewColumns", "Catalog", "@Catalog", "VIEW_CATALOG", 1},
1384 new object [] {"ViewColumns", "Owner", "@Owner", "VIEW_SCHEMA", 2},
1385 new object [] {"ViewColumns", "Table", "@Table", "VIEW_NAME", 3},
1386 new object [] {"ViewColumns", "Column", "@Column", "COLUMN_NAME", 4},
1388 new object [] {"ProcedureParameters", "Catalog", "@Catalog", "SPECIFIC_CATALOG", 1},
1389 new object [] {"ProcedureParameters", "Owner", "@Owner", "SPECIFIC_SCHEMA", 2},
1390 new object [] {"ProcedureParameters", "Name", "@Name", "SPECIFIC_NAME", 3},
1391 new object [] {"ProcedureParameters", "Parameter", "@Parameter", "PARAMETER_NAME", 4},
1393 new object [] {"Procedures", "Catalog", "@Catalog", "SPECIFIC_CATALOG", 1},
1394 new object [] {"Procedures", "Owner", "@Owner", "SPECIFIC_SCHEMA", 2},
1395 new object [] {"Procedures", "Name", "@Name", "SPECIFIC_NAME", 3},
1396 new object [] {"Procedures", "Type", "@Type", "ROUTINE_TYPE", 4},
1398 new object [] {"IndexColumns", "Catalog", "@Catalog", "db_name()", 1},
1399 new object [] {"IndexColumns", "Owner", "@Owner", "user_name()", 2},
1400 new object [] {"IndexColumns", "Table", "@Table", "o.name", 3},
1401 new object [] {"IndexColumns", "ConstraintName", "@ConstraintName", "x.name", 4},
1402 new object [] {"IndexColumns", "Column", "@Column", "c.name", 5},
1404 new object [] {"Indexes", "Catalog", "@Catalog", "db_name()", 1},
1405 new object [] {"Indexes", "Owner", "@Owner", "user_name()", 2},
1406 new object [] {"Indexes", "Table", "@Table", "o.name", 3},
1407 new object [] {"Indexes", "Name", "@Name", "x.name", 4},
1409 new object [] {"UserDefinedTypes", "assembly_name", "@AssemblyName", "assemblies.name", 1},
1410 new object [] {"UserDefinedTypes", "udt_name", "@UDTName", "types.assembly_class", 2},
1412 new object [] {"ForeignKeys", "Catalog", "@Catalog", "CONSTRAINT_CATALOG", 1},
1413 new object [] {"ForeignKeys", "Owner", "@Owner", "CONSTRAINT_SCHEMA", 2},
1414 new object [] {"ForeignKeys", "Table", "@Table", "TABLE_NAME", 3},
1415 new object [] {"ForeignKeys", "Name", "@Name", "CONSTRAINT_NAME", 4}
1418 static DataTable instance;
1419 static public DataTable Instance {
1421 if (instance == null) {
1422 instance = new DataTable ("Restrictions");
1423 foreach (ColumnInfo c in columns)
1424 instance.Columns.Add (c.name, c.type);
1425 foreach (object [] row in rows)
1426 instance.LoadDataRow (row, true);
1433 public override DataTable GetSchema ()
1435 if (state == ConnectionState.Closed)
1436 throw ExceptionHelper.ConnectionClosed ();
1438 return MetaDataCollections.Instance;
1441 public override DataTable GetSchema (String collectionName)
1443 return GetSchema (collectionName, null);
1446 public override DataTable GetSchema (String collectionName, string [] restrictionValues)
1448 // LAMESPEC: In MS.NET, if collectionName is null, it throws ArgumentException.
1450 if (state == ConnectionState.Closed)
1451 throw ExceptionHelper.ConnectionClosed ();
1453 String cName = null;
1454 DataTable schemaTable = MetaDataCollections.Instance;
1455 int length = restrictionValues == null ? 0 : restrictionValues.Length;
1457 foreach (DataRow row in schemaTable.Rows) {
1458 if (String.Compare ((string) row["CollectionName"], collectionName, true) == 0) {
1459 if (length > (int) row["NumberOfRestrictions"]) {
1460 throw new ArgumentException ("More restrictions were provided " +
1461 "than the requested schema ('" +
1462 row["CollectionName"].ToString () + "') supports");
1464 cName = row["CollectionName"].ToString();
1469 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
1470 "The requested collection ({0}) is not defined.",
1473 SqlCommand command = null;
1474 DataTable dataTable = new DataTable ();
1475 SqlDataAdapter dataAdapter = new SqlDataAdapter ();
1480 command = new SqlCommand ("select name as database_name, dbid, crdate as create_date " +
1481 "from master.sys.sysdatabases where (name = @Name or (@Name " +
1483 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1486 command = new SqlCommand ("select CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME, " +
1487 "TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_TYPE, " +
1488 "IS_DEFERRABLE, INITIALLY_DEFERRED from " +
1489 "INFORMATION_SCHEMA.TABLE_CONSTRAINTS where (CONSTRAINT_CATALOG" +
1490 " = @Catalog or (@Catalog is null)) and (CONSTRAINT_SCHEMA = " +
1491 "@Owner or (@Owner is null)) and (TABLE_NAME = @Table or (" +
1492 "@Table is null)) and (CONSTRAINT_NAME = @Name or (@Name is null))" +
1493 " and CONSTRAINT_TYPE = 'FOREIGN KEY' order by CONSTRAINT_CATALOG," +
1494 " CONSTRAINT_SCHEMA, CONSTRAINT_NAME", this);
1495 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1496 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1497 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1498 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1501 command = new SqlCommand ("select distinct db_name() as constraint_catalog, " +
1502 "constraint_schema = user_name (o.uid), " +
1503 "constraint_name = x.name, table_catalog = db_name (), " +
1504 "table_schema = user_name (o.uid), table_name = o.name, " +
1505 "index_name = x.name from sysobjects o, sysindexes x, " +
1506 "sysindexkeys xk where o.type in ('U') and x.id = o.id and " +
1507 "o.id = xk.id and x.indid = xk.indid and xk.keyno = x.keycnt " +
1508 "and (db_name() = @Catalog or (@Catalog is null)) and " +
1509 "(user_name() = @Owner or (@Owner is null)) and (o.name = " +
1510 "@Table or (@Table is null)) and (x.name = @Name or (@Name is null))" +
1511 "order by table_name, index_name", this);
1512 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1513 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1514 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1515 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1517 case "IndexColumns":
1518 command = new SqlCommand ("select distinct db_name() as constraint_catalog, " +
1519 "constraint_schema = user_name (o.uid), constraint_name = x.name, " +
1520 "table_catalog = db_name (), table_schema = user_name (o.uid), " +
1521 "table_name = o.name, column_name = c.name, " +
1522 "ordinal_position = convert (int, xk.keyno), keyType = c.xtype, " +
1523 "index_name = x.name from sysobjects o, sysindexes x, syscolumns c, " +
1524 "sysindexkeys xk where o.type in ('U') and x.id = o.id and o.id = c.id " +
1525 "and o.id = xk.id and x.indid = xk.indid and c.colid = xk.colid " +
1526 "and xk.keyno <= x.keycnt and permissions (o.id, c.name) <> 0 " +
1527 "and (db_name() = @Catalog or (@Catalog is null)) and (user_name() " +
1528 "= @Owner or (@Owner is null)) and (o.name = @Table or (@Table is" +
1529 " null)) and (x.name = @ConstraintName or (@ConstraintName is null)) " +
1530 "and (c.name = @Column or (@Column is null)) order by table_name, " +
1531 "index_name", this);
1532 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 8);
1533 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1534 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 13);
1535 command.Parameters.Add ("@ConstraintName", SqlDbType.NVarChar, 4000);
1536 command.Parameters.Add ("@Column", SqlDbType.NVarChar, 4000);
1539 command = new SqlCommand ("select SPECIFIC_CATALOG, SPECIFIC_SCHEMA, SPECIFIC_NAME, " +
1540 "ROUTINE_CATALOG, ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE, " +
1541 "CREATED, LAST_ALTERED from INFORMATION_SCHEMA.ROUTINES where " +
1542 "(SPECIFIC_CATALOG = @Catalog or (@Catalog is null)) and " +
1543 "(SPECIFIC_SCHEMA = @Owner or (@Owner is null)) and (SPECIFIC_NAME" +
1544 " = @Name or (@Name is null)) and (ROUTINE_TYPE = @Type or (@Type " +
1545 "is null)) order by SPECIFIC_CATALOG, SPECIFIC_SCHEMA, SPECIFIC_NAME", this);
1546 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1547 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1548 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1549 command.Parameters.Add ("@Type", SqlDbType.NVarChar, 4000);
1551 case "ProcedureParameters":
1552 command = new SqlCommand ("select SPECIFIC_CATALOG, SPECIFIC_SCHEMA, SPECIFIC_NAME, " +
1553 "ORDINAL_POSITION, PARAMETER_MODE, IS_RESULT, AS_LOCATOR, " +
1554 "PARAMETER_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, " +
1555 "CHARACTER_OCTET_LENGTH, COLLATION_CATALOG, COLLATION_SCHEMA, " +
1556 "COLLATION_NAME, CHARACTER_SET_CATALOG, CHARACTER_SET_SCHEMA, " +
1557 "CHARACTER_SET_NAME, NUMERIC_PRECISION, NUMERIC_PRECISION_RADIX, " +
1558 "NUMERIC_SCALE, DATETIME_PRECISION, INTERVAL_TYPE, " +
1559 "INTERVAL_PRECISION from INFORMATION_SCHEMA.PARAMETERS where " +
1560 "(SPECIFIC_CATALOG = @Catalog or (@Catalog is null)) and " +
1561 "(SPECIFIC_SCHEMA = @Owner or (@Owner is null)) and (SPECIFIC_NAME = " +
1562 "@Name or (@Name is null)) and (PARAMETER_NAME = @Parameter or (" +
1563 "@Parameter is null)) order by SPECIFIC_CATALOG, SPECIFIC_SCHEMA," +
1564 " SPECIFIC_NAME, PARAMETER_NAME", this);
1565 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1566 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1567 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1568 command.Parameters.Add ("@Parameter", SqlDbType.NVarChar, 4000);
1571 command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE " +
1572 "from INFORMATION_SCHEMA.TABLES where" +
1573 " (TABLE_CATALOG = @catalog or (@catalog is null)) and " +
1574 "(TABLE_SCHEMA = @owner or (@owner is null))and " +
1575 "(TABLE_NAME = @name or (@name is null)) and " +
1576 "(TABLE_TYPE = @table_type or (@table_type is null))", this);
1577 command.Parameters.Add ("@catalog", SqlDbType.NVarChar, 8);
1578 command.Parameters.Add ("@owner", SqlDbType.NVarChar, 3);
1579 command.Parameters.Add ("@name", SqlDbType.NVarChar, 11);
1580 command.Parameters.Add ("@table_type", SqlDbType.NVarChar, 10);
1583 command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, " +
1584 "ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, " +
1585 "CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH, " +
1586 "NUMERIC_PRECISION, NUMERIC_PRECISION_RADIX, NUMERIC_SCALE, " +
1587 "DATETIME_PRECISION, CHARACTER_SET_CATALOG, CHARACTER_SET_SCHEMA, " +
1588 "CHARACTER_SET_NAME, COLLATION_CATALOG from INFORMATION_SCHEMA.COLUMNS" +
1589 " where (TABLE_CATALOG = @Catalog or (@Catalog is null)) and (" +
1590 "TABLE_SCHEMA = @Owner or (@Owner is null)) and (TABLE_NAME = @table" +
1591 " or (@Table is null)) and (COLUMN_NAME = @column or (@Column is null" +
1592 ")) order by TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME", this);
1593 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1594 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1595 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1596 command.Parameters.Add ("@Column", SqlDbType.NVarChar, 4000);
1599 command = new SqlCommand ("select uid, name as user_name, createdate, updatedate from sysusers" +
1600 " where (name = @Name or (@Name is null))", this);
1601 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1603 case "StructuredTypeMembers":
1604 // Only available on SQL Server 2008
1605 // Running it again SQL 2005 results in the following exception:
1606 // Unable to build the 'StructuredTypeMembers' collection because
1607 // execution of the SQL query failed. See the inner exception for details.
1608 // ---> System.Data.SqlClient.SqlException: Invalid object name 'sys.table_types'.
1610 // I don't have access to SQL Server 2008 right now,
1611 // and can't find any online documentation on the 'sys.table_types'
1613 throw new NotImplementedException ();
1615 command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, CHECK_OPTION, " +
1616 "IS_UPDATABLE from INFORMATION_SCHEMA.VIEWS where (TABLE_CATALOG" +
1617 " = @Catalog or (@Catalog is null)) TABLE_SCHEMA = @Owner or " +
1618 "(@Owner is null)) and (TABLE_NAME = @table or (@Table is null))" +
1619 " order by TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME", this);
1620 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1621 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1622 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1625 command = new SqlCommand ("select VIEW_CATALOG, VIEW_SCHEMA, VIEW_NAME, TABLE_CATALOG, " +
1626 "TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from " +
1627 "INFORMATION_SCHEMA.VIEW_COLUMN_USAGE where (VIEW_CATALOG = " +
1628 "@Catalog (@Catalog is null)) and (VIEW_SCHEMA = @Owner (@Owner" +
1629 " is null)) and (VIEW_NAME = @Table or (@Table is null)) and " +
1630 "(COLUMN_NAME = @Column or (@Column is null)) order by " +
1631 "VIEW_CATALOG, VIEW_SCHEMA, VIEW_NAME", this);
1632 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1633 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1634 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1635 command.Parameters.Add ("@Column", SqlDbType.NVarChar, 4000);
1637 case "UserDefinedTypes":
1638 command = new SqlCommand ("select assemblies.name as assembly_name, types.assembly_class " +
1639 "as udt_name, ASSEMBLYPROPERTY(assemblies.name, 'VersionMajor') " +
1640 "as version_major, ASSEMBLYPROPERTY(assemblies.name, 'VersionMinor') " +
1641 "as version_minor, ASSEMBLYPROPERTY(assemblies.name, 'VersionBuild') " +
1642 "as version_build, ASSEMBLYPROPERTY(assemblies.name, 'VersionRevision') " +
1643 "as version_revision, ASSEMBLYPROPERTY(assemblies.name, 'CultureInfo') " +
1644 "as culture_info, ASSEMBLYPROPERTY(assemblies.name, 'PublicKey') " +
1645 "as public_key, is_fixed_length, max_length, Create_Date, " +
1646 "Permission_set_desc from sys.assemblies as assemblies join " +
1647 "sys.assembly_types as types on assemblies.assembly_id = types.assembly_id" +
1648 " where (assportemblies.name = @AssemblyName or (@AssemblyName is null)) and " +
1649 "(types.assembly_class = @UDTName or (@UDTName is null))",
1651 command.Parameters.Add ("@AssemblyName", SqlDbType.NVarChar, 4000);
1652 command.Parameters.Add ("@UDTName", SqlDbType.NVarChar, 4000);
1654 case "MetaDataCollections":
1655 return MetaDataCollections.Instance;
1656 case "DataSourceInformation":
1657 return DataSourceInformation.GetInstance (this);
1659 return DataTypes.Instance;
1660 case "ReservedWords":
1661 return ReservedWords.Instance;
1662 case "Restrictions":
1663 return Restrictions.Instance;
1665 for (int i = 0; i < length; i++) {
1666 command.Parameters[i].Value = restrictionValues[i];
1668 dataAdapter.SelectCommand = command;
1669 dataAdapter.Fill (dataTable);
1673 public static void ChangePassword (string connectionString, string newPassword)
1675 if (connectionString == null || newPassword == null || newPassword == String.Empty)
1676 throw new ArgumentNullException ();
1677 if (newPassword.Length > 128)
1678 throw new ArgumentException ("The value of newPassword exceeds its permittable length which is 128");
1679 using (SqlConnection conn = new SqlConnection (connectionString)) {
1681 conn.tds.Execute (String.Format ("sp_password '{0}', '{1}', '{2}'",
1682 conn.parms.Password, newPassword, conn.parms.User));
1686 public static void ClearAllPools ()
1688 Hashtable pools = SqlConnection.sqlConnectionPools.GetConnectionPool ();
1689 foreach (TdsConnectionPool pool in pools.Values) {
1691 pool.ResetConnectionPool ();
1692 ITds tds = pool.GetConnection ();
1693 tds.Pooling = false;
1698 public static void ClearPool (SqlConnection connection)
1700 if (connection.pooling) {
1701 connection.pooling = false;
1702 if (connection.pool != null)
1703 connection.pool.ResetConnectionPool (connection.Tds);
1709 #endregion // Methods
1712 #region Fields Net 2
1716 #endregion // Fields Net 2
1718 #region Properties Net 2
1721 [DataSysDescription ("Enable Asynchronous processing, 'Asynchrouse Processing=true/false' in the ConnectionString.")]
1723 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
1724 internal bool AsyncProcessing {
1725 get { return async; }
1728 #endregion // Properties Net 2