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;
49 using System.EnterpriseServices;
51 using System.Globalization;
53 using System.Net.Sockets;
56 using System.Collections.Generic;
57 using System.Security;
59 namespace System.Data.SqlClient
61 [DefaultEvent ("InfoMessage")]
62 public sealed class SqlConnection : DbConnection, IDbConnection, ICloneable
68 // The set of SQL connection pools
69 static TdsConnectionPoolManager sqlConnectionPools = new TdsConnectionPoolManager (TdsVersion.tds80);
70 const int DEFAULT_PACKETSIZE = 8000;
71 const int MAX_PACKETSIZE = 32768;
72 const int MIN_PACKETSIZE = 512;
73 const int DEFAULT_CONNECTIONTIMEOUT = 15;
74 const int DEFAULT_CONNECTIONLIFETIME = 0;
75 const int DEFAULT_MAXPOOLSIZE = 100;
76 const int MIN_MAXPOOLSIZE = 1;
77 const int DEFAULT_MINPOOLSIZE = 0;
78 const int DEFAULT_PORT = 1433;
80 // The current connection pool
81 TdsConnectionPool pool;
83 // The connection string that identifies this connection
84 string connectionString;
86 // The connection credentials
87 SqlCredential credentials;
89 // The transaction object for the current transaction
90 SqlTransaction transaction;
92 // Connection parameters
94 TdsConnectionParameters parms;
96 int connectionLifeTime;
99 int connectionTimeout;
104 bool fireInfoMessageEventOnUserErrors;
105 bool statisticsEnabled;
108 ConnectionState state = ConnectionState.Closed;
110 SqlDataReader dataReader;
120 public SqlConnection () : this (null)
124 public SqlConnection (string connectionString)
126 ConnectionString = connectionString;
129 public SqlConnection (string connectionString, SqlCredential cred)
131 ConnectionString = connectionString;
135 #endregion // Constructors
140 [EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
141 #pragma warning disable 618 // ignore obsolete warning about RecommendedAsConfigurable to use SettingsBindableAttribute
142 [RecommendedAsConfigurable(true)]
143 #pragma warning restore 618
144 [RefreshProperties (RefreshProperties.All)]
145 public override string ConnectionString {
147 if (connectionString == null)
149 return connectionString;
151 [MonoTODO("persist security info, encrypt, enlist keyword not implemented")]
153 if (state == ConnectionState.Open)
154 throw new InvalidOperationException ("Not Allowed to change ConnectionString property while Connection state is OPEN");
155 SetConnectionString (value);
159 public SqlCredential Credentials {
169 public Guid ClientConnectionId {
171 throw new NotImplementedException ();
175 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
178 int ConnectionTimeout {
179 get { return connectionTimeout; }
182 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
187 if (State == ConnectionState.Open)
189 return parms.Database ;
193 internal SqlDataReader DataReader {
194 get { return dataReader; }
195 set { dataReader = value; }
199 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
203 get { return dataSource; }
206 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
207 public int PacketSize {
209 if (State == ConnectionState.Open)
210 return ((Tds) tds).PacketSize;
216 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
219 string ServerVersion {
221 if (state == ConnectionState.Closed)
222 throw ExceptionHelper.ConnectionClosed ();
224 return tds.ServerVersion;
229 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
232 ConnectionState State {
233 get { return state; }
240 internal SqlTransaction Transaction {
241 get { return transaction; }
242 set { transaction = value; }
245 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
246 public string WorkstationId {
247 get { return parms.Hostname; }
250 internal XmlReader XmlReader {
251 get { return xmlReader; }
252 set { xmlReader = value; }
255 public bool FireInfoMessageEventOnUserErrors {
256 get { return fireInfoMessageEventOnUserErrors; }
257 set { fireInfoMessageEventOnUserErrors = value; }
260 [DefaultValue (false)]
261 public bool StatisticsEnabled {
262 get { return statisticsEnabled; }
263 set { statisticsEnabled = value; }
266 protected override DbProviderFactory DbProviderFactory {
268 return SqlClientFactory.Instance;
272 #endregion // Properties
276 public event SqlInfoMessageEventHandler InfoMessage;
283 private void ErrorHandler (object sender, TdsInternalErrorMessageEventArgs e)
286 if (!tds.IsConnected)
294 throw new SqlException (e.Class, e.LineNumber, e.Message, e.Number, e.Procedure, e.Server, "Mono SqlClient Data Provider", e.State);
297 private void MessageHandler (object sender, TdsInternalInfoMessageEventArgs e)
299 OnSqlInfoMessage (CreateSqlInfoMessageEvent (e.Errors));
302 #endregion // Delegates
306 public new SqlTransaction BeginTransaction ()
308 return BeginTransaction (IsolationLevel.ReadCommitted, String.Empty);
311 public new SqlTransaction BeginTransaction (IsolationLevel iso)
313 return BeginTransaction (iso, String.Empty);
316 public SqlTransaction BeginTransaction (string transactionName)
318 return BeginTransaction (IsolationLevel.ReadCommitted, transactionName);
321 public SqlTransaction BeginTransaction (IsolationLevel iso, string transactionName)
323 if (state == ConnectionState.Closed)
324 throw ExceptionHelper.ConnectionClosed ();
325 if (transaction != null)
326 throw new InvalidOperationException ("SqlConnection does not support parallel transactions.");
328 string isolevel = String.Empty;
330 case IsolationLevel.ReadUncommitted:
331 isolevel = "READ UNCOMMITTED";
333 case IsolationLevel.RepeatableRead:
334 isolevel = "REPEATABLE READ";
336 case IsolationLevel.Serializable:
337 isolevel = "SERIALIZABLE";
339 case IsolationLevel.ReadCommitted:
340 isolevel = "READ COMMITTED";
342 case IsolationLevel.Snapshot:
343 isolevel = "SNAPSHOT";
345 case IsolationLevel.Unspecified:
346 iso = IsolationLevel.ReadCommitted;
347 isolevel = "READ COMMITTED";
349 case IsolationLevel.Chaos:
350 throw new ArgumentOutOfRangeException ("IsolationLevel",
351 string.Format (CultureInfo.CurrentCulture,
352 "The IsolationLevel enumeration " +
353 "value, {0}, is not supported by " +
354 "the .Net Framework SqlClient " +
355 "Data Provider.", (int) iso));
357 throw new ArgumentOutOfRangeException ("IsolationLevel",
358 string.Format (CultureInfo.CurrentCulture,
359 "The IsolationLevel enumeration value, {0}, is invalid.",
363 tds.Execute (String.Format ("SET TRANSACTION ISOLATION LEVEL {0};BEGIN TRANSACTION {1}", isolevel, transactionName));
365 transaction = new SqlTransaction (this, iso);
371 void ChangeDatabase (string database)
373 if (!IsValidDatabaseName (database))
374 throw new ArgumentException (String.Format ("The database name {0} is not valid.", database));
375 if (state != ConnectionState.Open)
376 throw new InvalidOperationException ("The connection is not open.");
377 tds.Execute (String.Format ("use [{0}]", database));
380 private void ChangeState (ConnectionState currentState)
382 if (currentState == state)
385 ConnectionState originalState = state;
386 state = currentState;
387 OnStateChange (CreateStateChangeEvent (originalState, currentState));
394 if (transaction != null && transaction.IsOpen)
395 transaction.Rollback ();
397 if (dataReader != null || xmlReader != null) {
398 if(tds != null) tds.SkipToEnd ();
403 if (tds != null && tds.IsConnected) {
404 if (pooling && tds.Pooling) {
406 pool.ReleaseConnection (tds);
415 tds.TdsErrorMessage -= new TdsInternalErrorMessageEventHandler (ErrorHandler);
416 tds.TdsInfoMessage -= new TdsInternalInfoMessageEventHandler (MessageHandler);
419 ChangeState (ConnectionState.Closed);
422 public new SqlCommand CreateCommand ()
424 SqlCommand command = new SqlCommand ();
425 command.Connection = this;
429 private SqlInfoMessageEventArgs CreateSqlInfoMessageEvent (TdsInternalErrorCollection errors)
431 foreach (TdsInternalError e in errors)
432 return new SqlInfoMessageEventArgs (new SqlException (e.Class, e.LineNumber, e.Message, e.Number, e.Procedure, e.Server, "Mono SqlClient Data Provider", e.State));
437 private StateChangeEventArgs CreateStateChangeEvent (ConnectionState originalState, ConnectionState currentState)
439 return new StateChangeEventArgs (originalState, currentState);
442 protected override void Dispose (bool disposing)
445 if (disposing && !disposed) {
446 if (State == ConnectionState.Open)
448 ConnectionString = null;
452 base.Dispose (disposing);
457 [MonoTODO ("Not sure what this means at present.")]
458 public void EnlistDistributedTransaction (ITransaction transaction)
460 throw new NotImplementedException ();
464 object ICloneable.Clone ()
466 return new SqlConnection (ConnectionString);
469 protected override DbTransaction BeginDbTransaction (IsolationLevel isolationLevel)
471 return BeginTransaction (isolationLevel);
474 protected override DbCommand CreateDbCommand ()
476 return CreateCommand ();
483 string serverName = string.Empty;
484 if (state == ConnectionState.Open)
485 throw new InvalidOperationException ("The Connection is already Open (State=Open)");
487 if (connectionString == null || connectionString.Trim().Length == 0)
488 throw new InvalidOperationException ("Connection string has not been initialized.");
492 if(!ParseDataSource (dataSource, out port, out serverName))
493 throw new SqlException(20, 0, "SQL Server does not exist or access denied.", 17, "ConnectionOpen (Connect()).", dataSource, parms.ApplicationName, 0);
494 tds = new Tds80 (serverName, port, PacketSize, ConnectionTimeout, 0);
498 if(!ParseDataSource (dataSource, out port, out serverName))
499 throw new SqlException(20, 0, "SQL Server does not exist or access denied.", 17, "ConnectionOpen (Connect()).", dataSource, parms.ApplicationName, 0);
501 TdsConnectionInfo info = new TdsConnectionInfo (serverName, port, packetSize, ConnectionTimeout, minPoolSize, maxPoolSize, connectionLifeTime);
502 pool = sqlConnectionPools.GetConnectionPool (connectionString, info);
503 tds = pool.GetConnection ();
505 } catch (TdsTimeoutException e) {
506 throw SqlException.FromTdsInternalException ((TdsInternalException) e);
507 } catch (TdsInternalException e) {
508 throw SqlException.FromTdsInternalException (e);
511 tds.TdsErrorMessage += new TdsInternalErrorMessageEventHandler (ErrorHandler);
512 tds.TdsInfoMessage += new TdsInternalInfoMessageEventHandler (MessageHandler);
514 if (!tds.IsConnected) {
516 if (Credentials != null) {
517 if (parms.User != String.Empty)
518 throw new ArgumentException("UserID already specified");
519 if (parms.PasswordSet)
520 throw new ArgumentException("Password already specified");
521 if (parms.DomainLogin != false)
522 throw new ArgumentException("Cannot use credentials with DomainLogin");
523 parms.User = Credentials.UserId;
524 parms.Password = Credentials.Password;
529 pool.ReleaseConnection (tds);
534 disposed = false; // reset this, so using () would call Close ().
535 ChangeState (ConnectionState.Open);
538 private bool ParseDataSource (string theDataSource, out int thePort, out string theServerName)
540 theServerName = string.Empty;
541 string theInstanceName = string.Empty;
543 if (theDataSource == null)
544 throw new ArgumentException("Format of initialization string does not conform to specifications");
546 thePort = DEFAULT_PORT; // default TCP port for SQL Server
550 if ((idx = theDataSource.IndexOf (',')) > -1) {
551 theServerName = theDataSource.Substring (0, idx);
552 string p = theDataSource.Substring (idx + 1);
553 thePort = Int32.Parse (p);
554 } else if ((idx = theDataSource.IndexOf ('\\')) > -1) {
555 theServerName = theDataSource.Substring (0, idx);
556 theInstanceName = theDataSource.Substring (idx + 1);
558 // do port discovery via UDP port 1434
559 port = DiscoverTcpPortViaSqlMonitor (theServerName, theInstanceName);
563 theServerName = theDataSource;
565 if (theServerName.Length == 0 || theServerName == "(local)" || theServerName == ".")
566 theServerName = "localhost";
568 if ((idx = theServerName.IndexOf ("tcp:")) > -1)
569 theServerName = theServerName.Substring (idx + 4);
574 private bool ConvertIntegratedSecurity (string value)
576 if (value.ToUpper() == "SSPI")
579 return ConvertToBoolean ("integrated security", value, false);
582 private bool ConvertToBoolean (string key, string value, bool defaultValue)
584 if (value.Length == 0)
587 string upperValue = value.ToUpper ();
589 if (upperValue == "TRUE" || upperValue == "YES")
591 else if (upperValue == "FALSE" || upperValue == "NO")
594 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
595 "Invalid value \"{0}\" for key '{1}'.", value, key));
598 private int ConvertToInt32 (string key, string value, int defaultValue)
600 if (value.Length == 0)
604 return int.Parse (value);
605 } catch (Exception ex) {
606 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
607 "Invalid value \"{0}\" for key '{1}'.", value, key), ex);
611 private int DiscoverTcpPortViaSqlMonitor (string ServerName, string InstanceName)
613 SqlMonitorSocket msock;
614 msock = new SqlMonitorSocket (ServerName, InstanceName);
615 int SqlServerPort = msock.DiscoverTcpPort (ConnectionTimeout);
617 return SqlServerPort;
620 void SetConnectionString (string connectionString)
622 SetDefaultConnectionParameters ();
624 if ((connectionString == null) || (connectionString.Trim().Length == 0)) {
625 this.connectionString = connectionString;
629 connectionString += ";";
631 bool inQuote = false;
632 bool inDQuote = false;
635 string name = String.Empty;
636 string value = String.Empty;
637 StringBuilder sb = new StringBuilder ();
639 for (int i = 0; i < connectionString.Length; i += 1) {
640 char c = connectionString [i];
642 if (i == connectionString.Length - 1)
645 peek = connectionString [i + 1];
651 else if (peek.Equals (c)) {
661 else if (peek.Equals (c)) {
666 inDQuote = !inDQuote;
669 if (inDQuote || inQuote)
672 if (name != String.Empty && name != null) {
673 value = sb.ToString ();
674 SetProperties (name.ToLower ().Trim() , value);
676 else if (sb.Length != 0)
677 throw new ArgumentException ("Format of initialization string does not conform to specifications");
680 value = String.Empty;
681 sb = new StringBuilder ();
685 if (inDQuote || inQuote || !inName)
687 else if (peek.Equals (c)) {
693 name = sb.ToString ();
694 sb = new StringBuilder ();
699 if (inQuote || inDQuote)
701 else if (sb.Length > 0 && !peek.Equals (';'))
710 if (minPoolSize > maxPoolSize)
711 throw new ArgumentException ("Invalid value for "
712 + "'min pool size' or 'max pool size'; "
713 + "'min pool size' must not be greater "
714 + "than 'max pool size'.");
716 connectionString = connectionString.Substring (0 , connectionString.Length-1);
717 this.connectionString = connectionString;
720 void SetDefaultConnectionParameters ()
723 parms = new TdsConnectionParameters ();
726 dataSource = string.Empty;
727 connectionTimeout = DEFAULT_CONNECTIONTIMEOUT;
728 connectionLifeTime = DEFAULT_CONNECTIONLIFETIME;
729 connectionReset = true;
731 maxPoolSize = DEFAULT_MAXPOOLSIZE;
732 minPoolSize = DEFAULT_MINPOOLSIZE;
733 packetSize = DEFAULT_PACKETSIZE;
738 private void SetProperties (string name , string value)
742 case "application name" :
743 parms.ApplicationName = value;
745 case "attachdbfilename" :
746 case "extended properties" :
747 case "initial file name" :
748 parms.AttachDBFileName = value;
751 case "connect timeout" :
752 case "connection timeout" :
753 int tmpTimeout = ConvertToInt32 ("connect timeout", value,
754 DEFAULT_CONNECTIONTIMEOUT);
756 throw new ArgumentException ("Invalid 'connect timeout'. Must be an integer >=0 ");
758 connectionTimeout = tmpTimeout;
760 case "connection lifetime" :
761 connectionLifeTime = ConvertToInt32 ("connection lifetime", value, DEFAULT_CONNECTIONLIFETIME);
763 case "connection reset" :
764 connectionReset = ConvertToBoolean ("connection reset", value, true);
767 case "current language" :
768 parms.Language = value;
774 case "network address" :
778 if (ConvertToBoolean (name, value, false))
779 throw new NotImplementedException("SSL encryption for"
780 + " data sent between client and server is not"
784 if (!ConvertToBoolean (name, value, true))
785 throw new NotImplementedException("Disabling the automatic"
786 + " enlistment of connections in the thread's current"
787 + " transaction context is not implemented.");
789 case "initial catalog" :
791 parms.Database = value;
793 case "integrated security" :
794 case "trusted_connection" :
795 parms.DomainLogin = ConvertIntegratedSecurity(value);
797 case "max pool size" :
798 int tmpMaxPoolSize = ConvertToInt32 (name, value, DEFAULT_MAXPOOLSIZE);
799 if (tmpMaxPoolSize < MIN_MAXPOOLSIZE)
800 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
801 "Invalid '{0}'. The value must be greater than {1}.",
802 name, MIN_MAXPOOLSIZE));
804 maxPoolSize = tmpMaxPoolSize;
806 case "min pool size" :
807 int tmpMinPoolSize = ConvertToInt32 (name, value, DEFAULT_MINPOOLSIZE);
808 if (tmpMinPoolSize < 0)
809 throw new ArgumentException ("Invalid 'min pool size'. Must be a integer >= 0");
811 minPoolSize = tmpMinPoolSize;
813 case "multipleactiveresultsets":
814 // FIXME: not implemented
815 ConvertToBoolean (name, value, false);
817 case "asynchronous processing" :
819 async = ConvertToBoolean (name, value, false);
823 case "network library" :
824 if (!value.ToUpper ().Equals ("DBMSSOCN"))
825 throw new ArgumentException ("Unsupported network library.");
828 int tmpPacketSize = ConvertToInt32 (name, value, DEFAULT_PACKETSIZE);
829 if (tmpPacketSize < MIN_PACKETSIZE || tmpPacketSize > MAX_PACKETSIZE)
830 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
831 "Invalid 'Packet Size'. The value must be between {0} and {1}.",
832 MIN_PACKETSIZE, MAX_PACKETSIZE));
834 packetSize = tmpPacketSize;
838 parms.Password = new SecureString();
839 foreach (char c in value)
840 parms.Password.AppendChar(c);
841 parms.PasswordSet = true;
843 case "persistsecurityinfo" :
844 case "persist security info" :
845 // FIXME : not implemented
846 // throw new NotImplementedException ();
849 pooling = ConvertToBoolean (name, value, true);
857 case "workstation id" :
858 parms.Hostname = value;
860 case "user instance":
861 userInstance = ConvertToBoolean (name, value, false);
864 throw new ArgumentException("Keyword not supported : '" + name + "'.");
868 static bool IsValidDatabaseName (string database)
870 if ( database == null || database.Trim().Length == 0 || database.Length > 128)
873 if (database[0] == '"' && database[database.Length] == '"')
874 database = database.Substring (1, database.Length - 2);
875 else if (Char.IsDigit (database[0]))
878 if (database[0] == '_')
881 foreach (char c in database.Substring (1, database.Length - 1))
882 if (!Char.IsLetterOrDigit (c) && c != '_' && c != '-')
887 private void OnSqlInfoMessage (SqlInfoMessageEventArgs value)
889 if (InfoMessage != null)
890 InfoMessage (this, value);
894 private sealed class SqlMonitorSocket : UdpClient
896 // UDP port that the SQL Monitor listens
897 private static readonly int SqlMonitorUdpPort = 1434;
898 //private static readonly string SqlServerNotExist = "SQL Server does not exist or access denied";
900 private string server;
901 private string instance;
903 internal SqlMonitorSocket (string ServerName, string InstanceName)
904 : base (ServerName, SqlMonitorUdpPort)
907 instance = InstanceName;
910 internal int DiscoverTcpPort (int timeoutSeconds)
912 int SqlServerTcpPort;
913 Client.Blocking = false;
914 // send command to UDP 1434 (SQL Monitor) to get
915 // the TCP port to connect to the MS SQL server
916 ASCIIEncoding enc = new ASCIIEncoding ();
917 Byte[] rawrq = new Byte [instance.Length + 1];
919 enc.GetBytes (instance, 0, instance.Length, rawrq, 1);
920 Send (rawrq, rawrq.Length);
926 long timeout = timeoutSeconds * 1000000;
927 result = Client.Poll ((int)timeout, SelectMode.SelectRead);
931 if (Client.Available <= 0)
934 IPEndPoint endpoint = CreateLocalEndpoint ();
935 if (endpoint == null)
940 rawrs = Receive (ref endpoint);
942 string rs = Encoding.ASCII.GetString (rawrs);
944 string[] rawtokens = rs.Split (';');
945 Hashtable data = new Hashtable ();
946 for (int i = 0; i < rawtokens.Length / 2 && i < 256; i++) {
947 data [rawtokens [i * 2]] = rawtokens [ i * 2 + 1];
950 if (!data.ContainsKey ("tcp")) {
951 string msg = "Mono does not support names pipes or shared memory "
952 + "for connecting to SQL Server. Please enable the TCP/IP "
954 throw new NotImplementedException (msg);
957 SqlServerTcpPort = int.Parse ((string) data ["tcp"]);
960 return SqlServerTcpPort;
963 IPEndPoint CreateLocalEndpoint ()
965 foreach (var addr in Dns.GetHostEntry ("localhost").AddressList) {
966 if (addr.AddressFamily == Client.AddressFamily)
967 return new IPEndPoint (addr, 0);
979 public ColumnInfo (string name, Type type)
981 this.name = name; this.type = type;
985 static class ReservedWords
987 static readonly string [] reservedWords =
989 "ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER",
990 "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY",
991 "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE",
992 "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC",
993 "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ",
994 "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE",
995 "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK",
996 "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE",
997 "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN",
998 "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT",
999 "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY",
1000 "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL",
1001 "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE",
1002 "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT",
1003 "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT",
1004 "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE",
1005 "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE",
1006 "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER",
1007 "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT",
1008 "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN",
1009 "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD",
1010 "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK",
1011 "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER",
1012 "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL",
1013 "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF",
1014 "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS",
1015 "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN",
1016 "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE",
1017 "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW",
1018 "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN",
1019 "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL",
1020 "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT", "ABSOLUTE",
1021 "FOUND", "PRESERVE", "ACTION", "FREE", "PRIOR", "ADMIN",
1022 "GENERAL", "PRIVILEGES", "AFTER", "GET", "READS",
1023 "AGGREGATE", "GLOBAL", "REAL", "ALIAS", "GO", "RECURSIVE",
1024 "ALLOCATE", "GROUPING", "REF", "ARE", "HOST", "REFERENCING",
1025 "ARRAY", "HOUR", "RELATIVE", "ASSERTION", "IGNORE", "RESULT",
1026 "AT", "IMMEDIATE", "RETURNS", "BEFORE", "INDICATOR", "ROLE",
1027 "BINARY", "INITIALIZE", "ROLLUP", "BIT", "INITIALLY",
1028 "ROUTINE", "BLOB", "INOUT", "ROW", "BOOLEAN", "INPUT",
1029 "ROWS", "BOTH", "INT", "SAVEPOINT", "BREADTH", "INTEGER",
1030 "SCROLL", "CALL", "INTERVAL", "SCOPE", "CASCADED",
1031 "ISOLATION", "SEARCH", "CAST", "ITERATE", "SECOND",
1032 "CATALOG", "LANGUAGE", "SECTION", "CHAR", "LARGE",
1033 "SEQUENCE", "CHARACTER", "LAST", "SESSION", "CLASS",
1034 "LATERAL", "SETS", "CLOB", "LEADING", "SIZE", "COLLATION",
1035 "LESS", "SMALLINT", "COMPLETION", "LEVEL", "SPACE",
1036 "CONNECT", "LIMIT", "SPECIFIC", "CONNECTION", "LOCAL",
1037 "SPECIFICTYPE", "CONSTRAINTS", "LOCALTIME", "SQL",
1038 "CONSTRUCTOR", "LOCALTIMESTAMP", "SQLEXCEPTION",
1039 "CORRESPONDING", "LOCATOR", "SQLSTATE", "CUBE", "MAP",
1040 "SQLWARNING", "CURRENT_PATH", "MATCH", "START",
1041 "CURRENT_ROLE", "MINUTE", "STATE", "CYCLE", "MODIFIES",
1042 "STATEMENT", "DATA", "MODIFY", "STATIC", "DATE", "MODULE",
1043 "STRUCTURE", "DAY", "MONTH", "TEMPORARY", "DEC", "NAMES",
1044 "TERMINATE", "DECIMAL", "NATURAL", "THAN", "DEFERRABLE",
1045 "NCHAR", "TIME", "DEFERRED", "NCLOB", "TIMESTAMP", "DEPTH",
1046 "NEW", "TIMEZONE_HOUR", "DEREF", "NEXT", "TIMEZONE_MINUTE",
1047 "DESCRIBE", "NO", "TRAILING", "DESCRIPTOR", "NONE",
1048 "TRANSLATION", "DESTROY", "NUMERIC", "TREAT", "DESTRUCTOR",
1049 "OBJECT", "TRUE", "DETERMINISTIC", "OLD", "UNDER",
1050 "DICTIONARY", "ONLY", "UNKNOWN", "DIAGNOSTICS", "OPERATION",
1051 "UNNEST", "DISCONNECT", "ORDINALITY", "USAGE", "DOMAIN",
1052 "OUT", "USING", "DYNAMIC", "OUTPUT", "VALUE", "EACH",
1053 "PAD", "VARCHAR", "END-EXEC", "PARAMETER", "VARIABLE",
1054 "EQUALS", "PARAMETERS", "WHENEVER", "EVERY", "PARTIAL",
1055 "WITHOUT", "EXCEPTION", "PATH", "WORK", "EXTERNAL",
1056 "POSTFIX", "WRITE", "FALSE", "PREFIX", "YEAR", "FIRST",
1057 "PREORDER", "ZONE", "FLOAT", "PREPARE", "ADA", "AVG",
1058 "BIT_LENGTH", "CHAR_LENGTH", "CHARACTER_LENGTH", "COUNT",
1059 "EXTRACT", "FORTRAN", "INCLUDE", "INSENSITIVE", "LOWER",
1060 "MAX", "MIN", "OCTET_LENGTH", "OVERLAPS", "PASCAL",
1061 "POSITION", "SQLCA", "SQLCODE", "SQLERROR", "SUBSTRING",
1062 "SUM", "TRANSLATE", "TRIM", "UPPER"
1064 static DataTable instance;
1065 static public DataTable Instance {
1067 if (instance == null) {
1069 var newInstance = new DataTable ("ReservedWords");
1070 newInstance.Columns.Add ("ReservedWord", typeof(string));
1071 foreach (string reservedWord in reservedWords)
1073 row = newInstance.NewRow();
1075 row["ReservedWord"] = reservedWord;
1076 newInstance.Rows.Add(row);
1078 instance = newInstance;
1085 static class MetaDataCollections
1087 static readonly ColumnInfo [] columns = {
1088 new ColumnInfo ("CollectionName", typeof (string)),
1089 new ColumnInfo ("NumberOfRestrictions", typeof (int)),
1090 new ColumnInfo ("NumberOfIdentifierParts", typeof (int))
1093 static readonly object [][] rows = {
1094 new object [] {"MetaDataCollections", 0, 0},
1095 new object [] {"DataSourceInformation", 0, 0},
1096 new object [] {"DataTypes", 0, 0},
1097 new object [] {"Restrictions", 0, 0},
1098 new object [] {"ReservedWords", 0, 0},
1099 new object [] {"Users", 1, 1},
1100 new object [] {"Databases", 1, 1},
1101 new object [] {"Tables", 4, 3},
1102 new object [] {"Columns", 4, 4},
1103 new object [] {"StructuredTypeMembers", 4, 4},
1104 new object [] {"Views", 3, 3},
1105 new object [] {"ViewColumns", 4, 4},
1106 new object [] {"ProcedureParameters", 4, 1},
1107 new object [] {"Procedures", 4, 3},
1108 new object [] {"ForeignKeys", 4, 3},
1109 new object [] {"IndexColumns", 5, 4},
1110 new object [] {"Indexes", 4, 3},
1111 new object [] {"UserDefinedTypes", 2, 1}
1114 static DataTable instance;
1115 static public DataTable Instance {
1117 if (instance == null) {
1118 var newInstance = new DataTable ("MetaDataCollections");
1119 foreach (ColumnInfo c in columns)
1120 newInstance.Columns.Add (c.name, c.type);
1121 foreach (object [] row in rows)
1122 newInstance.LoadDataRow (row, true);
1123 instance = newInstance;
1130 static class DataSourceInformation
1132 static readonly ColumnInfo [] columns = {
1133 new ColumnInfo ("CompositeIdentifierSeparatorPattern", typeof (string)),
1134 new ColumnInfo ("DataSourceProductName", typeof(string)),
1135 new ColumnInfo ("DataSourceProductVersion", typeof(string)),
1136 new ColumnInfo ("DataSourceProductVersionNormalized", typeof(string)),
1137 new ColumnInfo ("GroupByBehavior", typeof(GroupByBehavior)),
1138 new ColumnInfo ("IdentifierPattern", typeof(string)),
1139 new ColumnInfo ("IdentifierCase", typeof(IdentifierCase)),
1140 new ColumnInfo ("OrderByColumnsInSelect", typeof(bool)),
1141 new ColumnInfo ("ParameterMarkerFormat", typeof(string)),
1142 new ColumnInfo ("ParameterMarkerPattern", typeof(string)),
1143 new ColumnInfo ("ParameterNameMaxLength", typeof(int)),
1144 new ColumnInfo ("ParameterNamePattern", typeof(string)),
1145 new ColumnInfo ("QuotedIdentifierPattern", typeof(string)),
1146 new ColumnInfo ("QuotedIdentifierCase", typeof(IdentifierCase)),
1147 new ColumnInfo ("StatementSeparatorPattern", typeof(string)),
1148 new ColumnInfo ("StringLiteralPattern", typeof(string)),
1149 new ColumnInfo ("SupportedJoinOperators", typeof(SupportedJoinOperators))
1152 static public DataTable GetInstance (SqlConnection conn)
1154 DataTable table = new DataTable ("DataSourceInformation");
1155 foreach (ColumnInfo c in columns)
1156 table.Columns.Add (c.name, c.type);
1157 DataRow row = table.NewRow ();
1159 row [1] = "Microsoft SQL Server";
1160 row [2] = conn.ServerVersion;;
1161 row [3] = conn.ServerVersion;;
1162 row [4] = GroupByBehavior.Unrelated;
1163 row [5] = @"(^\[\p{Lo}\p{Lu}\p{Ll}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Nd}@$#_]*$)|(^\[[^\]\0]|\]\]+\]$)|(^\""[^\""\0]|\""\""+\""$)";
1164 row [6] = IdentifierCase.Insensitive; // FIXME: obtain this from SQL Server
1167 row [9] = @"@[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)";
1169 row [11] = @"^[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)";
1170 row [12] = @"(([^\[]|\]\])*)";
1171 row [13] = IdentifierCase.Insensitive; // FIXME: obtain this from SQL Server
1173 row [15] = "'(([^']|'')*)'";
1174 row [16] = (SupportedJoinOperators.FullOuter | SupportedJoinOperators.Inner |
1175 SupportedJoinOperators.LeftOuter | SupportedJoinOperators.RightOuter);
1176 table.Rows.Add (row);
1181 static class DataTypes
1183 static readonly ColumnInfo [] columns = {
1184 new ColumnInfo ("TypeName", typeof(string)),
1185 new ColumnInfo ("ProviderDbType", typeof(int)),
1186 new ColumnInfo ("ColumnSize", typeof(long)),
1187 new ColumnInfo ("CreateFormat", typeof(string)),
1188 new ColumnInfo ("CreateParameters", typeof(string)),
1189 new ColumnInfo ("DataType", typeof(string)),
1190 new ColumnInfo ("IsAutoIncrementable", typeof(bool)),
1191 new ColumnInfo ("IsBestMatch", typeof(bool)),
1192 new ColumnInfo ("IsCaseSensitive", typeof(bool)),
1193 new ColumnInfo ("IsFixedLength", typeof(bool)),
1194 new ColumnInfo ("IsFixedPrecisionScale", typeof(bool)),
1195 new ColumnInfo ("IsLong", typeof(bool)),
1196 new ColumnInfo ("IsNullable", typeof(bool)),
1197 new ColumnInfo ("IsSearchable", typeof(bool)),
1198 new ColumnInfo ("IsSearchableWithLike", typeof(bool)),
1199 new ColumnInfo ("IsUnsigned", typeof(bool)),
1200 new ColumnInfo ("MaximumScale", typeof(short)),
1201 new ColumnInfo ("MinimumScale", typeof(short)),
1202 new ColumnInfo ("IsConcurrencyType", typeof(bool)),
1203 new ColumnInfo ("IsLiteralSupported", typeof(bool)),
1204 new ColumnInfo ("LiteralPrefix", typeof(string)),
1205 new ColumnInfo ("LiteralSuffix", typeof(string))
1208 static readonly object [][] rows = {
1209 new object [] {"smallint", 16, 5, "smallint", null, "System.Int16", true, true,
1210 false, true, true, false, true, true, false, false, null,
1211 null, false, null, null, null},
1212 new object [] {"int", 8, 10, "int", null, "System.Int32",
1213 true, true, false, true, true, false, true, true, false,
1214 false, null, null, false, null, null, null},
1215 new object [] {"real", 13, 7, "real", null,
1216 "System.Single", false, true, false, true, false, false,
1217 true, true, false, false, null, null, false, null, null, null},
1218 new object [] {"float", 6, 53, "float({0})",
1219 "number of bits used to store the mantissa", "System.Double",
1220 false, true, false, true, false, false, true, true,
1221 false, false, null, null, false, null, null, null},
1222 new object [] {"money", 9, 19, "money", null,
1223 "System.Decimal", false, false, false, true, true,
1224 false, true, true, false, false, null, null, false,
1226 new object [] {"smallmoney", 17, 10, "smallmoney", null,
1227 "System.Decimal", false, false, false, true, true, false,
1228 true, true, false, false, null, null, false, null, null, null},
1229 new object [] {"bit", 2, 1, "bit", null, "System.Boolean",
1230 false, false, false, true, false, false, true, true,
1231 false, null, null, null, false, null, null, null},
1232 new object [] {"tinyint", 20, 3, "tinyint", null,
1233 "System.SByte", true, true, false, true, true, false,
1234 true, true, false, true, null, null, false, null, null, null},
1235 new object [] {"bigint", 0, 19, "bigint", null,
1236 "System.Int64", true, true, false, true, true, false,
1237 true, true, false, false, null, null, false, null, null, null},
1238 new object [] {"timestamp", 19, 8, "timestamp", null,
1239 "System.Byte[]", false, false, false, true, false, false,
1240 false, true, false, null, null, null, true, null, "0x", null},
1241 new object [] {"binary", 1, 8000, "binary({0})", "length",
1242 "System.Byte[]", false, true, false, true, false, false,
1243 true, true, false, null, null, null, false, null, "0x", null},
1244 new object [] {"image", 7, 2147483647, "image", null,
1245 "System.Byte[]", false, true, false, false, false, true,
1246 true, false, false, null, null, null, false, null, "0x", null},
1247 new object [] {"text", 18, 2147483647, "text", null,
1248 "System.String", false, true, false, false, false, true,
1249 true, false, true, null, null, null, false, null, "'", "'"},
1250 new object [] {"ntext", 11, 1073741823, "ntext", null,
1251 "System.String", false, true, false, false, false, true,
1252 true, false, true, null, null, null, false, null, "N'", "'"},
1253 new object [] {"decimal", 5, 38, "decimal({0}, {1})",
1254 "precision,scale", "System.Decimal", true, true, false,
1255 true, false, false, true, true, false, false, 38, 0,
1256 false, null, null, null},
1257 new object [] {"numeric", 5, 38, "numeric({0}, {1})",
1258 "precision,scale", "System.Decimal", true, true, false,
1259 true, false, false, true, true, false, false, 38, 0,
1260 false, null, null, null},
1261 new object [] {"datetime", 4, 23, "datetime", null,
1262 "System.DateTime", false, true, false, true, false, false,
1263 true, true, true, null, null, null, false, null, "{ts '", "'}"},
1264 new object [] {"smalldatetime", 15, 16, "smalldatetime", null,
1265 "System.DateTime", false, true, false, true, false, false,
1266 true, true, true, null, null, null, false, null, "{ts '", "'}"},
1267 new object [] {"sql_variant", 23, null, "sql_variant",
1268 null, "System.Object", false, true, false, false, false,
1269 false, true, true, false, null, null, null, false, false,
1271 new object [] {"xml", 25, 2147483647, "xml", null,
1272 "System.String", false, false, false, false, false, true,
1273 true, false, false, null, null, null, false, false, null, null},
1274 new object [] {"varchar", 22, 2147483647, "varchar({0})",
1275 "max length", "System.String", false, true, false, false,
1276 false, false, true, true, true, null, null, null, false,
1278 new object [] {"char", 3, 2147483647, "char({0})", "length",
1279 "System.String", false, true, false, true, false, false,
1280 true, true, true, null, null, null, false, null, "'", "'"},
1281 new object [] {"nchar", 10, 1073741823, "nchar({0})", "length",
1282 "System.String", false, true, false, true, false, false,
1283 true, true, true, null, null, null, false, null, "N'", "'"},
1284 new object [] {"nvarchar", 12, 1073741823, "nvarchar({0})", "max length",
1285 "System.String", false, true, false, false, false, false, true, true,
1286 true, null, null, null, false, null, "N'", "'"},
1287 new object [] {"varbinary", 21, 1073741823, "varbinary({0})",
1288 "max length", "System.Byte[]", false, true, false, false,
1289 false, false, true, true, false, null, null, null, false,
1291 new object [] {"uniqueidentifier", 14, 16, "uniqueidentifier", null,
1292 "System.Guid", false, true, false, true, false, false, true,
1293 true, false, null, null, null, false, null, "'", "'"},
1294 new object [] {"date", 31, 3L, "date", DBNull.Value,
1295 "System.DateTime", false, false, false, true, true, false,
1296 true, true, true, DBNull.Value, DBNull.Value, DBNull.Value,
1297 false, DBNull.Value, "{ts '", "'}"},
1298 new object [] {"time", 32, 5L, "time({0})", "scale",
1299 "System.TimeSpan", false, false, false, false, false, false,
1300 true, true, true, DBNull.Value, (short) 7, (short) 0,
1301 false, DBNull.Value, "{ts '", "'}"},
1302 new object [] {"datetime2", 33, 8L, "datetime2({0})", "scale",
1303 "System.DateTime", false, true, false, false, false, false,
1304 true, true, true, DBNull.Value, (short) 7, (short) 0,
1305 false, DBNull.Value, "{ts '", "'}"},
1306 new object [] {"datetimeoffset", 34, 10L, "datetimeoffset({0})",
1307 "scale", "System.DateTimeOffset", false, true, false, false,
1308 false, false, true, true, true, DBNull.Value, (short) 7, (short) 0,
1309 false, DBNull.Value, "{ts '", "'}"}
1312 static DataTable instance;
1313 static public DataTable Instance {
1315 if (instance == null) {
1316 instance = new DataTable ("DataTypes");
1317 foreach (ColumnInfo c in columns)
1318 instance.Columns.Add (c.name, c.type);
1319 foreach (object [] row in rows)
1320 instance.LoadDataRow (row, true);
1327 static class Restrictions
1329 static readonly ColumnInfo [] columns = {
1330 new ColumnInfo ("CollectionName", typeof (string)),
1331 new ColumnInfo ("RestrictionName", typeof(string)),
1332 new ColumnInfo ("ParameterName", typeof(string)),
1333 new ColumnInfo ("RestrictionDefault", typeof(string)),
1334 new ColumnInfo ("RestrictionNumber", typeof(int))
1337 static readonly object [][] rows = {
1338 new object [] {"Users", "User_Name", "@Name", "name", 1},
1339 new object [] {"Databases", "Name", "@Name", "Name", 1},
1341 new object [] {"Tables", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
1342 new object [] {"Tables", "Owner", "@Owner", "TABLE_SCHEMA", 2},
1343 new object [] {"Tables", "Table", "@Name", "TABLE_NAME", 3},
1344 new object [] {"Tables", "TableType", "@TableType", "TABLE_TYPE", 4},
1346 new object [] {"Columns", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
1347 new object [] {"Columns", "Owner", "@Owner", "TABLE_SCHEMA", 2},
1348 new object [] {"Columns", "Table", "@Table", "TABLE_NAME", 3},
1349 new object [] {"Columns", "Column", "@Column", "COLUMN_NAME", 4},
1351 new object [] {"StructuredTypeMembers", "Catalog", "@Catalog", "TYPE_CATALOG", 1},
1352 new object [] {"StructuredTypeMembers", "Owner", "@Owner", "TYPE_SCHEMA", 2},
1353 new object [] {"StructuredTypeMembers", "Type", "@Type", "TYPE_NAME", 3},
1354 new object [] {"StructuredTypeMembers", "Member", "@Member", "MEMBER_NAME", 4},
1356 new object [] {"Views", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
1357 new object [] {"Views", "Owner", "@Owner", "TABLE_SCHEMA", 2},
1358 new object [] {"Views", "Table", "@Table", "TABLE_NAME", 3},
1360 new object [] {"ViewColumns", "Catalog", "@Catalog", "VIEW_CATALOG", 1},
1361 new object [] {"ViewColumns", "Owner", "@Owner", "VIEW_SCHEMA", 2},
1362 new object [] {"ViewColumns", "Table", "@Table", "VIEW_NAME", 3},
1363 new object [] {"ViewColumns", "Column", "@Column", "COLUMN_NAME", 4},
1365 new object [] {"ProcedureParameters", "Catalog", "@Catalog", "SPECIFIC_CATALOG", 1},
1366 new object [] {"ProcedureParameters", "Owner", "@Owner", "SPECIFIC_SCHEMA", 2},
1367 new object [] {"ProcedureParameters", "Name", "@Name", "SPECIFIC_NAME", 3},
1368 new object [] {"ProcedureParameters", "Parameter", "@Parameter", "PARAMETER_NAME", 4},
1370 new object [] {"Procedures", "Catalog", "@Catalog", "SPECIFIC_CATALOG", 1},
1371 new object [] {"Procedures", "Owner", "@Owner", "SPECIFIC_SCHEMA", 2},
1372 new object [] {"Procedures", "Name", "@Name", "SPECIFIC_NAME", 3},
1373 new object [] {"Procedures", "Type", "@Type", "ROUTINE_TYPE", 4},
1375 new object [] {"IndexColumns", "Catalog", "@Catalog", "db_name()", 1},
1376 new object [] {"IndexColumns", "Owner", "@Owner", "user_name()", 2},
1377 new object [] {"IndexColumns", "Table", "@Table", "o.name", 3},
1378 new object [] {"IndexColumns", "ConstraintName", "@ConstraintName", "x.name", 4},
1379 new object [] {"IndexColumns", "Column", "@Column", "c.name", 5},
1381 new object [] {"Indexes", "Catalog", "@Catalog", "db_name()", 1},
1382 new object [] {"Indexes", "Owner", "@Owner", "user_name()", 2},
1383 new object [] {"Indexes", "Table", "@Table", "o.name", 3},
1384 new object [] {"Indexes", "Name", "@Name", "x.name", 4},
1386 new object [] {"UserDefinedTypes", "assembly_name", "@AssemblyName", "assemblies.name", 1},
1387 new object [] {"UserDefinedTypes", "udt_name", "@UDTName", "types.assembly_class", 2},
1389 new object [] {"ForeignKeys", "Catalog", "@Catalog", "CONSTRAINT_CATALOG", 1},
1390 new object [] {"ForeignKeys", "Owner", "@Owner", "CONSTRAINT_SCHEMA", 2},
1391 new object [] {"ForeignKeys", "Table", "@Table", "TABLE_NAME", 3},
1392 new object [] {"ForeignKeys", "Name", "@Name", "CONSTRAINT_NAME", 4}
1395 static DataTable instance;
1396 static public DataTable Instance {
1398 if (instance == null) {
1399 instance = new DataTable ("Restrictions");
1400 foreach (ColumnInfo c in columns)
1401 instance.Columns.Add (c.name, c.type);
1402 foreach (object [] row in rows)
1403 instance.LoadDataRow (row, true);
1410 public override DataTable GetSchema ()
1412 if (state == ConnectionState.Closed)
1413 throw ExceptionHelper.ConnectionClosed ();
1415 return MetaDataCollections.Instance;
1418 public override DataTable GetSchema (String collectionName)
1420 return GetSchema (collectionName, null);
1423 public override DataTable GetSchema (String collectionName, string [] restrictionValues)
1425 // LAMESPEC: In MS.NET, if collectionName is null, it throws ArgumentException.
1427 if (state == ConnectionState.Closed)
1428 throw ExceptionHelper.ConnectionClosed ();
1430 String cName = null;
1431 DataTable schemaTable = MetaDataCollections.Instance;
1432 int length = restrictionValues == null ? 0 : restrictionValues.Length;
1434 foreach (DataRow row in schemaTable.Rows) {
1435 if (String.Compare ((string) row["CollectionName"], collectionName, true) == 0) {
1436 if (length > (int) row["NumberOfRestrictions"]) {
1437 throw new ArgumentException ("More restrictions were provided " +
1438 "than the requested schema ('" +
1439 row["CollectionName"].ToString () + "') supports");
1441 cName = row["CollectionName"].ToString();
1446 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
1447 "The requested collection ({0}) is not defined.",
1450 SqlCommand command = null;
1451 DataTable dataTable = new DataTable ();
1452 SqlDataAdapter dataAdapter = new SqlDataAdapter ();
1457 command = new SqlCommand ("select name as database_name, dbid, crdate as create_date " +
1458 "from master.sys.sysdatabases where (name = @Name or (@Name " +
1460 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1463 command = new SqlCommand ("select CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME, " +
1464 "TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_TYPE, " +
1465 "IS_DEFERRABLE, INITIALLY_DEFERRED from " +
1466 "INFORMATION_SCHEMA.TABLE_CONSTRAINTS where (CONSTRAINT_CATALOG" +
1467 " = @Catalog or (@Catalog is null)) and (CONSTRAINT_SCHEMA = " +
1468 "@Owner or (@Owner is null)) and (TABLE_NAME = @Table or (" +
1469 "@Table is null)) and (CONSTRAINT_NAME = @Name or (@Name is null))" +
1470 " and CONSTRAINT_TYPE = 'FOREIGN KEY' order by CONSTRAINT_CATALOG," +
1471 " CONSTRAINT_SCHEMA, CONSTRAINT_NAME", this);
1472 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1473 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1474 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1475 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1478 command = new SqlCommand ("select distinct db_name() as constraint_catalog, " +
1479 "constraint_schema = user_name (o.uid), " +
1480 "constraint_name = x.name, table_catalog = db_name (), " +
1481 "table_schema = user_name (o.uid), table_name = o.name, " +
1482 "index_name = x.name from sysobjects o, sysindexes x, " +
1483 "sysindexkeys xk where o.type in ('U') and x.id = o.id and " +
1484 "o.id = xk.id and x.indid = xk.indid and xk.keyno = x.keycnt " +
1485 "and (db_name() = @Catalog or (@Catalog is null)) and " +
1486 "(user_name() = @Owner or (@Owner is null)) and (o.name = " +
1487 "@Table or (@Table is null)) and (x.name = @Name or (@Name is null))" +
1488 "order by table_name, index_name", this);
1489 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1490 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1491 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1492 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1494 case "IndexColumns":
1495 command = new SqlCommand ("select distinct db_name() as constraint_catalog, " +
1496 "constraint_schema = user_name (o.uid), constraint_name = x.name, " +
1497 "table_catalog = db_name (), table_schema = user_name (o.uid), " +
1498 "table_name = o.name, column_name = c.name, " +
1499 "ordinal_position = convert (int, xk.keyno), keyType = c.xtype, " +
1500 "index_name = x.name from sysobjects o, sysindexes x, syscolumns c, " +
1501 "sysindexkeys xk where o.type in ('U') and x.id = o.id and o.id = c.id " +
1502 "and o.id = xk.id and x.indid = xk.indid and c.colid = xk.colid " +
1503 "and xk.keyno <= x.keycnt and permissions (o.id, c.name) <> 0 " +
1504 "and (db_name() = @Catalog or (@Catalog is null)) and (user_name() " +
1505 "= @Owner or (@Owner is null)) and (o.name = @Table or (@Table is" +
1506 " null)) and (x.name = @ConstraintName or (@ConstraintName is null)) " +
1507 "and (c.name = @Column or (@Column is null)) order by table_name, " +
1508 "index_name", this);
1509 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 8);
1510 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1511 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 13);
1512 command.Parameters.Add ("@ConstraintName", SqlDbType.NVarChar, 4000);
1513 command.Parameters.Add ("@Column", SqlDbType.NVarChar, 4000);
1516 command = new SqlCommand ("select SPECIFIC_CATALOG, SPECIFIC_SCHEMA, SPECIFIC_NAME, " +
1517 "ROUTINE_CATALOG, ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE, " +
1518 "CREATED, LAST_ALTERED from INFORMATION_SCHEMA.ROUTINES where " +
1519 "(SPECIFIC_CATALOG = @Catalog or (@Catalog is null)) and " +
1520 "(SPECIFIC_SCHEMA = @Owner or (@Owner is null)) and (SPECIFIC_NAME" +
1521 " = @Name or (@Name is null)) and (ROUTINE_TYPE = @Type or (@Type " +
1522 "is null)) order by SPECIFIC_CATALOG, SPECIFIC_SCHEMA, SPECIFIC_NAME", this);
1523 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1524 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1525 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1526 command.Parameters.Add ("@Type", SqlDbType.NVarChar, 4000);
1528 case "ProcedureParameters":
1529 command = new SqlCommand ("select SPECIFIC_CATALOG, SPECIFIC_SCHEMA, SPECIFIC_NAME, " +
1530 "ORDINAL_POSITION, PARAMETER_MODE, IS_RESULT, AS_LOCATOR, " +
1531 "PARAMETER_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, " +
1532 "CHARACTER_OCTET_LENGTH, COLLATION_CATALOG, COLLATION_SCHEMA, " +
1533 "COLLATION_NAME, CHARACTER_SET_CATALOG, CHARACTER_SET_SCHEMA, " +
1534 "CHARACTER_SET_NAME, NUMERIC_PRECISION, NUMERIC_PRECISION_RADIX, " +
1535 "NUMERIC_SCALE, DATETIME_PRECISION, INTERVAL_TYPE, " +
1536 "INTERVAL_PRECISION from INFORMATION_SCHEMA.PARAMETERS where " +
1537 "(SPECIFIC_CATALOG = @Catalog or (@Catalog is null)) and " +
1538 "(SPECIFIC_SCHEMA = @Owner or (@Owner is null)) and (SPECIFIC_NAME = " +
1539 "@Name or (@Name is null)) and (PARAMETER_NAME = @Parameter or (" +
1540 "@Parameter is null)) order by SPECIFIC_CATALOG, SPECIFIC_SCHEMA," +
1541 " SPECIFIC_NAME, PARAMETER_NAME", this);
1542 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1543 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1544 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1545 command.Parameters.Add ("@Parameter", SqlDbType.NVarChar, 4000);
1548 command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE " +
1549 "from INFORMATION_SCHEMA.TABLES where" +
1550 " (TABLE_CATALOG = @catalog or (@catalog is null)) and " +
1551 "(TABLE_SCHEMA = @owner or (@owner is null))and " +
1552 "(TABLE_NAME = @name or (@name is null)) and " +
1553 "(TABLE_TYPE = @table_type or (@table_type is null))", this);
1554 command.Parameters.Add ("@catalog", SqlDbType.NVarChar, 8);
1555 command.Parameters.Add ("@owner", SqlDbType.NVarChar, 3);
1556 command.Parameters.Add ("@name", SqlDbType.NVarChar, 11);
1557 command.Parameters.Add ("@table_type", SqlDbType.NVarChar, 10);
1560 command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, " +
1561 "ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, " +
1562 "CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH, " +
1563 "NUMERIC_PRECISION, NUMERIC_PRECISION_RADIX, NUMERIC_SCALE, " +
1564 "DATETIME_PRECISION, CHARACTER_SET_CATALOG, CHARACTER_SET_SCHEMA, " +
1565 "CHARACTER_SET_NAME, COLLATION_CATALOG from INFORMATION_SCHEMA.COLUMNS" +
1566 " where (TABLE_CATALOG = @Catalog or (@Catalog is null)) and (" +
1567 "TABLE_SCHEMA = @Owner or (@Owner is null)) and (TABLE_NAME = @table" +
1568 " or (@Table is null)) and (COLUMN_NAME = @column or (@Column is null" +
1569 ")) order by TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME", this);
1570 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1571 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1572 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1573 command.Parameters.Add ("@Column", SqlDbType.NVarChar, 4000);
1576 command = new SqlCommand ("select uid, name as user_name, createdate, updatedate from sysusers" +
1577 " where (name = @Name or (@Name is null))", this);
1578 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1580 case "StructuredTypeMembers":
1581 // Only available on SQL Server 2008
1582 // Running it again SQL 2005 results in the following exception:
1583 // Unable to build the 'StructuredTypeMembers' collection because
1584 // execution of the SQL query failed. See the inner exception for details.
1585 // ---> System.Data.SqlClient.SqlException: Invalid object name 'sys.table_types'.
1587 // I don't have access to SQL Server 2008 right now,
1588 // and can't find any online documentation on the 'sys.table_types'
1590 throw new NotImplementedException ();
1592 command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, CHECK_OPTION, " +
1593 "IS_UPDATABLE from INFORMATION_SCHEMA.VIEWS where (TABLE_CATALOG" +
1594 " = @Catalog or (@Catalog is null)) TABLE_SCHEMA = @Owner or " +
1595 "(@Owner is null)) and (TABLE_NAME = @table or (@Table is null))" +
1596 " order by TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME", this);
1597 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1598 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1599 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1602 command = new SqlCommand ("select VIEW_CATALOG, VIEW_SCHEMA, VIEW_NAME, TABLE_CATALOG, " +
1603 "TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from " +
1604 "INFORMATION_SCHEMA.VIEW_COLUMN_USAGE where (VIEW_CATALOG = " +
1605 "@Catalog (@Catalog is null)) and (VIEW_SCHEMA = @Owner (@Owner" +
1606 " is null)) and (VIEW_NAME = @Table or (@Table is null)) and " +
1607 "(COLUMN_NAME = @Column or (@Column is null)) order by " +
1608 "VIEW_CATALOG, VIEW_SCHEMA, VIEW_NAME", this);
1609 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1610 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1611 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1612 command.Parameters.Add ("@Column", SqlDbType.NVarChar, 4000);
1614 case "UserDefinedTypes":
1615 command = new SqlCommand ("select assemblies.name as assembly_name, types.assembly_class " +
1616 "as udt_name, ASSEMBLYPROPERTY(assemblies.name, 'VersionMajor') " +
1617 "as version_major, ASSEMBLYPROPERTY(assemblies.name, 'VersionMinor') " +
1618 "as version_minor, ASSEMBLYPROPERTY(assemblies.name, 'VersionBuild') " +
1619 "as version_build, ASSEMBLYPROPERTY(assemblies.name, 'VersionRevision') " +
1620 "as version_revision, ASSEMBLYPROPERTY(assemblies.name, 'CultureInfo') " +
1621 "as culture_info, ASSEMBLYPROPERTY(assemblies.name, 'PublicKey') " +
1622 "as public_key, is_fixed_length, max_length, Create_Date, " +
1623 "Permission_set_desc from sys.assemblies as assemblies join " +
1624 "sys.assembly_types as types on assemblies.assembly_id = types.assembly_id" +
1625 " where (assportemblies.name = @AssemblyName or (@AssemblyName is null)) and " +
1626 "(types.assembly_class = @UDTName or (@UDTName is null))",
1628 command.Parameters.Add ("@AssemblyName", SqlDbType.NVarChar, 4000);
1629 command.Parameters.Add ("@UDTName", SqlDbType.NVarChar, 4000);
1631 case "MetaDataCollections":
1632 return MetaDataCollections.Instance;
1633 case "DataSourceInformation":
1634 return DataSourceInformation.GetInstance (this);
1636 return DataTypes.Instance;
1637 case "ReservedWords":
1638 return ReservedWords.Instance;
1639 case "Restrictions":
1640 return Restrictions.Instance;
1642 for (int i = 0; i < length; i++) {
1643 command.Parameters[i].Value = restrictionValues[i];
1645 dataAdapter.SelectCommand = command;
1646 dataAdapter.Fill (dataTable);
1650 public static void ChangePassword (string connectionString, string newPassword)
1652 if (String.IsNullOrEmpty (connectionString))
1653 throw new ArgumentNullException ("The 'connectionString' cannot be null or empty.");
1654 if (String.IsNullOrEmpty (newPassword))
1655 throw new ArgumentNullException ("The 'newPassword' cannot be null or empty.");
1656 if (newPassword.Length > 128)
1657 throw new ArgumentException ("The length of 'newPassword' cannot exceed 128 characters.");
1658 using (SqlConnection conn = new SqlConnection (connectionString)) {
1660 conn.tds.Execute (String.Format ("sp_password '{0}', '{1}', '{2}'",
1661 conn.parms.Password, newPassword, conn.parms.User));
1665 public static void ClearAllPools ()
1668 IDictionary pools = SqlConnection.sqlConnectionPools.GetConnectionPool ();
1669 foreach (TdsConnectionPool pool in pools.Values) {
1671 pool.ResetConnectionPool ();
1676 public static void ClearPool (SqlConnection connection)
1678 if (connection == null)
1679 throw new ArgumentNullException ("connection");
1682 if (connection.pooling) {
1683 TdsConnectionPool pool = sqlConnectionPools.GetConnectionPool (connection.ConnectionString);
1685 pool.ResetConnectionPool ();
1690 public void ResetStatistics ()
1692 throw new NotImplementedException ();
1696 public IDictionary RetrieveStatistics ()
1698 throw new NotImplementedException ();
1701 #endregion // Methods
1703 #region Fields Net 2
1708 #endregion // Fields Net 2
1710 #region Properties Net 2
1712 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
1713 internal bool AsyncProcessing {
1714 get { return async; }
1717 #endregion // Properties Net 2