* SqlConnection.cs(ChangeState): Return immediately when new state
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlConnection.cs
1 //
2 // System.Data.SqlClient.SqlConnection.cs
3 //
4 // Authors:
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)
10 //
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
15 //
16
17 //
18 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
19 //
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:
27 // 
28 // The above copyright notice and this permission notice shall be
29 // included in all copies or substantial portions of the Software.
30 // 
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.
38 //
39
40 using Mono.Data.Tds;
41 using Mono.Data.Tds.Protocol;
42 using System;
43 using System.Collections;
44 using System.Collections.Specialized;
45 using System.ComponentModel;
46 using System.Data;
47 using System.Data.Common;
48 using System.EnterpriseServices;
49 using System.Globalization;
50 using System.Net;
51 using System.Net.Sockets;
52 using System.Text;
53 using System.Xml;
54 #if NET_2_0
55 using System.Collections.Generic;
56 #endif
57
58 namespace System.Data.SqlClient
59 {
60         [DefaultEvent ("InfoMessage")]
61 #if NET_2_0
62         public sealed class SqlConnection : DbConnection, IDbConnection, ICloneable
63 #else
64         public sealed class SqlConnection : Component, IDbConnection, ICloneable
65 #endif // NET_2_0
66         {
67                 #region Fields
68
69                 bool disposed;
70
71                 // The set of SQL connection pools
72                 static TdsConnectionPoolManager sqlConnectionPools = new TdsConnectionPoolManager (TdsVersion.tds70);
73 #if NET_2_0
74                 const int DEFAULT_PACKETSIZE = 8000;
75 #else
76                 const int DEFAULT_PACKETSIZE = 8192;
77 #endif
78                 const int DEFAULT_CONNECTIONTIMEOUT = 15;
79                 const int DEFAULT_MAXPOOLSIZE = 100;
80                 const int DEFAULT_MINPOOLSIZE = 0;
81                 const int DEFAULT_PORT = 1433;
82
83                 // The current connection pool
84                 TdsConnectionPool pool;
85
86                 // The connection string that identifies this connection
87                 string connectionString;
88
89                 // The transaction object for the current transaction
90                 SqlTransaction transaction;
91
92                 // Connection parameters
93                 
94                 TdsConnectionParameters parms = new TdsConnectionParameters ();
95                 bool connectionReset;
96                 bool pooling;
97                 string dataSource;
98                 int connectionTimeout;
99                 int minPoolSize;
100                 int maxPoolSize;
101                 int packetSize;
102                 int port;
103                 bool fireInfoMessageEventOnUserErrors;
104                 bool statisticsEnabled;
105                 bool userInstance;
106                 
107                 // The current state
108                 ConnectionState state = ConnectionState.Closed;
109
110                 SqlDataReader dataReader;
111                 XmlReader xmlReader;
112
113                 // The TDS object
114                 Tds tds;
115
116                 #endregion // Fields
117
118                 #region Constructors
119
120                 public SqlConnection () : this (String.Empty)
121                 {
122                 }
123         
124                 public SqlConnection (string connectionString)
125                 {
126                         Init (connectionString);
127                 }
128
129                 private void Init (string connectionString)
130                 {
131                         connectionTimeout = DEFAULT_CONNECTIONTIMEOUT;
132                         dataSource = string.Empty;
133                         packetSize = DEFAULT_PACKETSIZE;
134                         port = DEFAULT_PORT;
135                         ConnectionString = connectionString;
136                 }
137
138                 #endregion // Constructors
139
140                 #region Properties
141
142 #if NET_1_0 || ONLY_1_1
143                 [DataSysDescription ("Information used to connect to a DataSource, such as 'Data Source=x;Initial Catalog=x;Integrated Security=SSPI'.")]
144 #endif
145                 [DefaultValue ("")]
146                 [EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
147                 [RecommendedAsConfigurable (true)]
148                 [RefreshProperties (RefreshProperties.All)]
149                 public
150 #if NET_2_0
151                 override
152 #endif // NET_2_0
153                 string ConnectionString {
154                         get {
155                                 if (connectionString == null)
156                                         return string.Empty;
157                                 return connectionString;
158                         }
159                         [MonoTODO("persist security info, encrypt, enlist keyword not implemented")]
160                         set {
161                                 if (state == ConnectionState.Open)
162                                         throw new InvalidOperationException ("Not Allowed to change ConnectionString property while Connection state is OPEN");
163                                 SetConnectionString (value); 
164                         }
165                 }
166         
167 #if !NET_2_0
168                 [DataSysDescription ("Current connection timeout value, 'Connect Timeout=X' in the ConnectionString.")] 
169 #endif
170                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
171                 public
172 #if NET_2_0
173                 override
174 #endif // NET_2_0
175                 int ConnectionTimeout {
176                         get { return connectionTimeout; }
177                 }
178
179 #if !NET_2_0
180                 [DataSysDescription ("Current SQL Server database, 'Initial Catalog=X' in the connection string.")]
181 #endif
182                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
183                 public
184 #if NET_2_0
185                 override
186 #endif // NET_2_0
187                 string Database {
188                         get {
189                                 if (State == ConnectionState.Open)
190                                         return tds.Database; 
191                                 return parms.Database ;
192                         }
193                 }
194                 
195                 internal SqlDataReader DataReader {
196                         get { return dataReader; }
197                         set { dataReader = value; }
198                 }
199
200 #if !NET_2_0
201                 [DataSysDescription ("Current SqlServer that the connection is opened to, 'Data Source=X' in the connection string. ")]
202 #else
203                 [Browsable(true)]
204 #endif
205                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
206                 public
207 #if NET_2_0
208                 override
209 #endif // NET_2_0
210                 string DataSource {
211                         get { return dataSource; }
212                 }
213
214 #if !NET_2_0
215                 [DataSysDescription ("Network packet size, 'Packet Size=x' in the connection string.")]
216 #endif
217                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
218                 public int PacketSize {
219                         get {
220                                 if (State == ConnectionState.Open)
221                                         return ((Tds) tds).PacketSize;
222                                 return packetSize;
223                         }
224                 }
225
226                 [Browsable (false)]
227 #if !NET_2_0
228                 [DataSysDescription ("Version of the SQL Server accessed by the SqlConnection.")]
229 #endif
230                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
231                 public
232 #if NET_2_0
233                 override
234 #endif // NET_2_0
235                 string ServerVersion {
236                         get {
237                                 if (state == ConnectionState.Closed)
238                                         throw ExceptionHelper.ConnectionClosed ();
239                                 else
240                                         return tds.ServerVersion; 
241                         }
242                 }
243
244                 [Browsable (false)]
245 #if !NET_2_0
246                 [DataSysDescription ("The ConnectionState indicating whether the connection is open or closed.")]
247 #endif
248                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
249                 public
250 #if NET_2_0
251                 override
252 #endif // NET_2_0
253                 ConnectionState State {
254                         get { return state; }
255                 }
256
257                 internal Tds Tds {
258                         get { return tds; }
259                 }
260
261                 internal SqlTransaction Transaction {
262                         get { return transaction; }
263                         set { transaction = value; }
264                 }
265
266 #if !NET_2_0
267                 [DataSysDescription ("Workstation Id, 'Workstation ID=x' in the connection string.")]
268 #endif
269                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
270                 public string WorkstationId {
271                         get { return parms.Hostname; }
272                 }
273
274                 internal XmlReader XmlReader {
275                         get { return xmlReader; }
276                         set { xmlReader = value; }
277                 }
278
279 #if NET_2_0
280                 public bool FireInfoMessageEventOnUserErrors { 
281                         get { return fireInfoMessageEventOnUserErrors; } 
282                         set { fireInfoMessageEventOnUserErrors = value; }
283                 }
284                 
285                 [DefaultValue (false)]
286                 public bool StatisticsEnabled { 
287                         get { return statisticsEnabled; } 
288                         set { statisticsEnabled = value; }
289                 }
290 #endif
291                 #endregion // Properties
292
293                 #region Events
294
295 #if !NET_2_0
296                 [DataSysDescription ("Event triggered when messages arrive from the DataSource.")]
297 #endif
298                 public event SqlInfoMessageEventHandler InfoMessage;
299
300 #if !NET_2_0
301                 [DataSysDescription ("Event triggered when the connection changes state.")]
302                 public new event StateChangeEventHandler StateChange;
303 #endif
304
305                 #endregion // Events
306
307                 #region Delegates
308
309                 private void ErrorHandler (object sender, TdsInternalErrorMessageEventArgs e)
310                 {
311                         throw new SqlException (e.Class, e.LineNumber, e.Message, e.Number, e.Procedure, e.Server, "Mono SqlClient Data Provider", e.State);
312                 }
313
314                 private void MessageHandler (object sender, TdsInternalInfoMessageEventArgs e)
315                 {
316                         OnSqlInfoMessage (CreateSqlInfoMessageEvent (e.Errors));
317                 }
318
319                 #endregion // Delegates
320
321                 #region Methods
322
323                 public new SqlTransaction BeginTransaction ()
324                 {
325                         return BeginTransaction (IsolationLevel.ReadCommitted, String.Empty);
326                 }
327
328                 public new SqlTransaction BeginTransaction (IsolationLevel iso)
329                 {
330                         return BeginTransaction (iso, String.Empty);
331                 }
332
333                 public SqlTransaction BeginTransaction (string transactionName)
334                 {
335                         return BeginTransaction (IsolationLevel.ReadCommitted, transactionName);
336                 }
337
338                 public SqlTransaction BeginTransaction (IsolationLevel iso, string transactionName)
339                 {
340                         if (state == ConnectionState.Closed)
341                                 throw ExceptionHelper.ConnectionClosed ();
342                         if (transaction != null)
343                                 throw new InvalidOperationException ("SqlConnection does not support parallel transactions.");
344
345                         string isolevel = String.Empty;
346                         switch (iso) {
347                         case IsolationLevel.ReadUncommitted:
348                                 isolevel = "READ UNCOMMITTED";
349                                 break;
350                         case IsolationLevel.RepeatableRead:
351                                 isolevel = "REPEATABLE READ";
352                                 break;
353                         case IsolationLevel.Serializable:
354                                 isolevel = "SERIALIZABLE";
355                                 break;
356                         case IsolationLevel.ReadCommitted:
357                                 isolevel = "READ COMMITTED";
358                                 break;
359 #if NET_2_0
360                         case IsolationLevel.Snapshot:
361                                 isolevel = "SNAPSHOT";
362                                 break;
363                         case IsolationLevel.Unspecified:
364                                 iso = IsolationLevel.ReadCommitted;
365                                 isolevel = "READ COMMITTED";
366                                 break;
367                         case IsolationLevel.Chaos:
368                                 throw new ArgumentOutOfRangeException ("IsolationLevel",
369                                         string.Format (CultureInfo.CurrentCulture,
370                                                 "The IsolationLevel enumeration " +
371                                                 "value, {0}, is not supported by " +
372                                                 "the .Net Framework SqlClient " +
373                                                 "Data Provider.", (int) iso));
374 #endif
375                         default:
376 #if NET_2_0
377                                 throw new ArgumentOutOfRangeException ("IsolationLevel",
378                                         string.Format (CultureInfo.CurrentCulture,
379                                                 "The IsolationLevel enumeration value, {0}, is invalid.",
380                                                 (int) iso));
381 #else
382                                 throw new ArgumentException ("Invalid IsolationLevel parameter: must be ReadCommitted, ReadUncommitted, RepeatableRead, or Serializable.");
383 #endif
384                         }
385
386                         tds.Execute (String.Format ("SET TRANSACTION ISOLATION LEVEL {0};BEGIN TRANSACTION {1}", isolevel, transactionName));
387                         
388                         transaction = new SqlTransaction (this, iso);
389                         return transaction;
390                 }
391
392                 public
393 #if NET_2_0
394                 override
395 #endif // NET_2_0
396                 void ChangeDatabase (string database)
397                 {
398                         if (!IsValidDatabaseName (database))
399                                 throw new ArgumentException (String.Format ("The database name {0} is not valid.", database));
400                         if (state != ConnectionState.Open)
401                                 throw new InvalidOperationException ("The connection is not open.");
402                         tds.Execute (String.Format ("use [{0}]", database));
403                 }
404
405                 private void ChangeState (ConnectionState currentState)
406                 {
407                         if (currentState == state)
408                                 return;
409
410                         ConnectionState originalState = state;
411                         state = currentState;
412                         OnStateChange (CreateStateChangeEvent (originalState, currentState));
413                 }
414
415                 public
416 #if NET_2_0
417                 override
418 #endif // NET_2_0
419                 void Close ()
420                 {
421                         if (transaction != null && transaction.IsOpen)
422                                 transaction.Rollback ();
423
424                         if (dataReader != null || xmlReader != null) {
425                                 if(tds != null) tds.SkipToEnd ();
426                                 dataReader = null;
427                                 xmlReader = null;
428                         }
429
430                         if (tds != null && tds.IsConnected) {
431                                 if (pooling && tds.Pooling) {
432 #if NET_2_0
433                                         if(pool != null) pool.ReleaseConnection (ref tds);
434 #else
435                                         if(pool != null) pool.ReleaseConnection (tds);
436 #endif
437                                 }else
438                                         if(tds != null) tds.Disconnect ();
439                         }
440
441                         if (tds != null) {
442                                 tds.TdsErrorMessage -= new TdsInternalErrorMessageEventHandler (ErrorHandler);
443                                 tds.TdsInfoMessage -= new TdsInternalInfoMessageEventHandler (MessageHandler);
444                         }
445
446                         ChangeState (ConnectionState.Closed);
447                 }
448
449                 public new SqlCommand CreateCommand ()
450                 {
451                         SqlCommand command = new SqlCommand ();
452                         command.Connection = this;
453                         return command;
454                 }
455                 
456                 private SqlInfoMessageEventArgs CreateSqlInfoMessageEvent (TdsInternalErrorCollection errors)
457                 {
458                         return new SqlInfoMessageEventArgs (errors);
459                 }
460
461                 private StateChangeEventArgs CreateStateChangeEvent (ConnectionState originalState, ConnectionState currentState)
462                 {
463                         return new StateChangeEventArgs (originalState, currentState);
464                 }
465
466                 protected override void Dispose (bool disposing)
467                 {
468                         if (disposed)
469                                 return;
470
471                         try {
472                                 if (disposing) {
473                                         if (State == ConnectionState.Open) 
474                                                 Close ();
475                                         ConnectionString = string.Empty;
476                                 }
477                         } finally {
478                                 disposed = true;
479                                 base.Dispose (disposing);
480                         }
481                 }
482
483                 [MonoTODO ("Not sure what this means at present.")]
484                 public void EnlistDistributedTransaction (ITransaction transaction)
485                 {
486                         throw new NotImplementedException ();
487                 }
488
489                 object ICloneable.Clone ()
490                 {
491                         return new SqlConnection (ConnectionString);
492                 }
493
494 #if NET_2_0
495                 protected override DbTransaction BeginDbTransaction (IsolationLevel isolationLevel)
496                 {
497                         return BeginTransaction (isolationLevel);
498                 }
499
500                 protected override DbCommand CreateDbCommand ()
501                 {
502                         return CreateCommand ();
503                 }
504 #else
505                 IDbTransaction IDbConnection.BeginTransaction ()
506                 {
507                         return BeginTransaction ();
508                 }
509
510                 IDbTransaction IDbConnection.BeginTransaction (IsolationLevel iso)
511                 {
512                         return BeginTransaction (iso);
513                 }
514
515                 IDbCommand IDbConnection.CreateCommand ()
516                 {
517                         return CreateCommand ();
518                 }
519 #endif
520
521                 public
522 #if NET_2_0
523                 override
524 #endif // NET_2_0
525                 void Open ()
526                 {
527                         string serverName = string.Empty;
528                         if (state == ConnectionState.Open)
529                                 throw new InvalidOperationException ("The Connection is already Open (State=Open)");
530
531                         if (connectionString == null || connectionString.Trim().Length == 0)
532                                 throw new InvalidOperationException ("Connection string has not been initialized.");
533
534                         try {
535                                 if (!pooling) {
536                                         if(!ParseDataSource (dataSource, out port, out serverName))
537                                                 throw new SqlException(20, 0, "SQL Server does not exist or access denied.",  17, "ConnectionOpen (Connect()).", dataSource, parms.ApplicationName, 0);
538                                         tds = new Tds70 (serverName, port, PacketSize, ConnectionTimeout);
539                                 }
540                                 else {
541                                         if(!ParseDataSource (dataSource, out port, out serverName))
542                                                 throw new SqlException(20, 0, "SQL Server does not exist or access denied.",  17, "ConnectionOpen (Connect()).", dataSource, parms.ApplicationName, 0);
543                                         
544                                         TdsConnectionInfo info = new TdsConnectionInfo (serverName, port, packetSize, ConnectionTimeout, minPoolSize, maxPoolSize);
545                                         pool = sqlConnectionPools.GetConnectionPool (connectionString, info);
546                                         tds = pool.GetConnection ();
547                                 }
548                         } catch (TdsTimeoutException e) {
549                                 throw SqlException.FromTdsInternalException ((TdsInternalException) e);
550                         } catch (TdsInternalException e) {
551                                 throw SqlException.FromTdsInternalException (e);
552                         }
553
554                         tds.TdsErrorMessage += new TdsInternalErrorMessageEventHandler (ErrorHandler);
555                         tds.TdsInfoMessage += new TdsInternalInfoMessageEventHandler (MessageHandler);
556
557                         if (!tds.IsConnected) {
558                                 try {
559                                         tds.Connect (parms);
560                                 } catch {
561                                         if (pooling)
562                                                 pool.ReleaseConnection (tds);
563                                         throw;
564                                 }
565                         }
566
567                         disposed = false; // reset this, so using () would call Close ().
568                         ChangeState (ConnectionState.Open);
569                 }
570
571                 private bool ParseDataSource (string theDataSource, out int thePort, out string theServerName)
572                 {
573                         theServerName = string.Empty;
574                         string theInstanceName = string.Empty;
575         
576                         if (theDataSource == null)
577                                 throw new ArgumentException("Format of initialization string does not conform to specifications");
578
579                         thePort = DEFAULT_PORT; // default TCP port for SQL Server
580                         bool success = true;
581
582                         int idx = 0;
583                         if ((idx = theDataSource.IndexOf (",")) > -1) {
584                                 theServerName = theDataSource.Substring (0, idx);
585                                 string p = theDataSource.Substring (idx + 1);
586                                 thePort = Int32.Parse (p);
587                         } else if ((idx = theDataSource.IndexOf ("\\")) > -1) {
588                                 theServerName = theDataSource.Substring (0, idx);
589                                 theInstanceName = theDataSource.Substring (idx + 1);
590
591                                 // do port discovery via UDP port 1434
592                                 port = DiscoverTcpPortViaSqlMonitor (theServerName, theInstanceName);
593                                 if (port == -1)
594                                         success = false;
595                         } else
596                                 theServerName = theDataSource;
597
598                         if (theServerName.Length == 0 || theServerName == "(local)" || theServerName == ".")
599                                 theServerName = "localhost";
600
601                         if ((idx = theServerName.IndexOf ("tcp:")) > -1)
602                                 theServerName = theServerName.Substring (idx + 4);
603
604                         return success;
605                 }
606
607                 private bool ConvertIntegratedSecurity (string value)
608                 {
609                         if (value.ToUpper() == "SSPI")
610                                 return true;
611
612                         return ConvertToBoolean("integrated security", value);
613                 }
614
615                 private bool ConvertToBoolean (string key, string value)
616                 {
617                         string upperValue = value.ToUpper ();
618
619                         if (upperValue == "TRUE" || upperValue == "YES")
620                                 return true;
621                         else if (upperValue == "FALSE" || upperValue == "NO")
622                                 return false;
623
624                         throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
625                                 "Invalid value \"{0}\" for key '{1}'.", value, key));
626                 }
627
628                 private int ConvertToInt32 (string key, string value)
629                 {
630                         try {
631                                 return int.Parse (value);
632                         } catch (Exception ex) {
633                                 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
634                                         "Invalid value \"{0}\" for key '{1}'.", value, key));
635                         }
636                 }
637
638                 private int DiscoverTcpPortViaSqlMonitor (string ServerName, string InstanceName) 
639                 {
640                         SqlMonitorSocket msock;
641                         msock = new SqlMonitorSocket (ServerName, InstanceName);
642                         int SqlServerPort = msock.DiscoverTcpPort (ConnectionTimeout);
643                         msock = null;
644                         return SqlServerPort;
645                 }
646         
647                 void SetConnectionString (string connectionString)
648                 {
649                         SetDefaultConnectionParameters ();
650
651                         if ((connectionString == null) || (connectionString.Trim().Length == 0)) {
652                                 this.connectionString = connectionString;
653                                 return;
654                         }
655
656                         connectionString += ";";
657
658                         bool inQuote = false;
659                         bool inDQuote = false;
660                         bool inName = true;
661
662                         string name = String.Empty;
663                         string value = String.Empty;
664                         StringBuilder sb = new StringBuilder ();
665
666                         for (int i = 0; i < connectionString.Length; i += 1) {
667                                 char c = connectionString [i];
668                                 char peek;
669                                 if (i == connectionString.Length - 1)
670                                         peek = '\0';
671                                 else
672                                         peek = connectionString [i + 1];
673
674                                 switch (c) {
675                                 case '\'':
676                                         if (inDQuote)
677                                                 sb.Append (c);
678                                         else if (peek.Equals (c)) {
679                                                 sb.Append (c);
680                                                 i += 1;
681                                         }
682                                         else
683                                                 inQuote = !inQuote;
684                                         break;
685                                 case '"':
686                                         if (inQuote)
687                                                 sb.Append (c);
688                                         else if (peek.Equals (c)) {
689                                                 sb.Append (c);
690                                                 i += 1;
691                                         }
692                                         else
693                                                 inDQuote = !inDQuote;
694                                         break;
695                                 case ';':
696                                         if (inDQuote || inQuote)
697                                                 sb.Append (c);
698                                         else {
699                                                 if (name != String.Empty && name != null) {
700                                                         value = sb.ToString ();
701                                                         SetProperties (name.ToUpper ().Trim() , value);
702                                                 }
703                                                 else if (sb.Length != 0)
704                                                         throw new ArgumentException ("Format of initialization string does not conform to specifications");
705                                                 inName = true;
706                                                 name = String.Empty;
707                                                 value = String.Empty;
708                                                 sb = new StringBuilder ();
709                                         }
710                                         break;
711                                 case '=':
712                                         if (inDQuote || inQuote || !inName)
713                                                 sb.Append (c);
714                                         else if (peek.Equals (c)) {
715                                                 sb.Append (c);
716                                                 i += 1;
717
718                                         }
719                                         else {
720                                                 name = sb.ToString ();
721                                                 sb = new StringBuilder ();
722                                                 inName = false;
723                                         }
724                                         break;
725                                 case ' ':
726                                         if (inQuote || inDQuote)
727                                                 sb.Append (c);
728                                         else if (sb.Length > 0 && !peek.Equals (';'))
729                                                 sb.Append (c);
730                                         break;
731                                 default:
732                                         sb.Append (c);
733                                         break;
734                                 }
735                         }
736
737                         connectionString = connectionString.Substring (0 , connectionString.Length-1);
738                         this.connectionString = connectionString;
739                 }
740
741                 void SetDefaultConnectionParameters ()
742                 {
743                         parms.Reset ();
744                         dataSource = string.Empty;
745                         connectionTimeout = DEFAULT_CONNECTIONTIMEOUT;
746                         connectionReset = true;
747                         pooling = true;
748                         maxPoolSize = DEFAULT_MAXPOOLSIZE;
749                         minPoolSize = DEFAULT_MINPOOLSIZE;
750                         packetSize = DEFAULT_PACKETSIZE;
751  #if NET_2_0
752                         async = false;
753  #endif
754                 }
755
756                 private void SetProperties (string name , string value)
757                 {
758                         switch (name) {
759                         case "APP" :
760                         case "APPLICATION NAME" :
761                                 parms.ApplicationName = value;
762                                 break;
763                         case "ATTACHDBFILENAME" :
764                         case "EXTENDED PROPERTIES" :
765                         case "INITIAL FILE NAME" :
766                                 parms.AttachDBFileName = value;
767                                 break;
768                         case "TIMEOUT" :
769                         case "CONNECT TIMEOUT" :
770                         case "CONNECTION TIMEOUT" :
771                                 int tmpTimeout = ConvertToInt32 ("connection timeout", value);
772                                 if (tmpTimeout < 0)
773                                         throw new ArgumentException ("Invalid CONNECTION TIMEOUT .. Must be an integer >=0 ");
774                                 else 
775                                         connectionTimeout = tmpTimeout;
776                                 break;
777                         case "CONNECTION LIFETIME" :
778                                 break;
779                         case "CONNECTION RESET" :
780                                 connectionReset = ConvertToBoolean ("connection reset", value);
781                                 break;
782                         case "LANGUAGE" :
783                         case "CURRENT LANGUAGE" :
784                                 parms.Language = value;
785                                 break;
786                         case "DATA SOURCE" :
787                         case "SERVER" :
788                         case "ADDRESS" :
789                         case "ADDR" :
790                         case "NETWORK ADDRESS" :
791                                 dataSource = value;
792                                 break;
793                         case "ENCRYPT":
794                                 if (ConvertToBoolean("encrypt", value))
795                                         throw new NotImplementedException("SSL encryption for"
796                                                 + " data sent between client and server is not"
797                                                 + " implemented.");
798                                 break;
799                         case "ENLIST" :
800                                 if (!ConvertToBoolean("enlist", value))
801                                         throw new NotImplementedException("Disabling the automatic"
802                                                 + " enlistment of connections in the thread's current"
803                                                 + " transaction context is not implemented.");
804                                 break;
805                         case "INITIAL CATALOG" :
806                         case "DATABASE" :
807                                 parms.Database = value;
808                                 break;
809                         case "INTEGRATED SECURITY" :
810                         case "TRUSTED_CONNECTION" :
811                                 parms.DomainLogin = ConvertIntegratedSecurity(value);
812                                 break;
813                         case "MAX POOL SIZE" :
814                                 int tmpMaxPoolSize = ConvertToInt32 ("max pool size" , value);
815                                 if (tmpMaxPoolSize < 0)
816                                         throw new ArgumentException ("Invalid MAX POOL SIZE. Must be a intger >= 0");
817                                 else
818                                         maxPoolSize = tmpMaxPoolSize;
819                                 break;
820                         case "MIN POOL SIZE" :
821                                 int tmpMinPoolSize = ConvertToInt32 ("min pool size" , value);
822                                 if (tmpMinPoolSize < 0)
823                                         throw new ArgumentException ("Invalid MIN POOL SIZE. Must be a intger >= 0");
824                                 else
825                                         minPoolSize = tmpMinPoolSize;
826                                 break;
827 #if NET_2_0     
828                         case "MULTIPLEACTIVERESULTSETS":
829                                 break;
830                         case "ASYNCHRONOUS PROCESSING" :
831                         case "ASYNC" :
832                                 async = ConvertToBoolean (name, value);
833                                 break;
834 #endif  
835                         case "NET" :
836                         case "NETWORK" :
837                         case "NETWORK LIBRARY" :
838                                 if (!value.ToUpper ().Equals ("DBMSSOCN"))
839                                         throw new ArgumentException ("Unsupported network library.");
840                                 break;
841                         case "PACKET SIZE" :
842                                 int tmpPacketSize = ConvertToInt32 ("packet size", value);
843                                 if (tmpPacketSize < 512 || tmpPacketSize > 32767)
844                                         throw new ArgumentException ("Invalid PACKET SIZE. The integer must be between 512 and 32767");
845                                 else
846                                         packetSize = tmpPacketSize;
847                                 break;
848                         case "PASSWORD" :
849                         case "PWD" :
850                                 parms.Password = value;
851                                 break;
852                         case "PERSISTSECURITYINFO" :
853                         case "PERSIST SECURITY INFO" :
854                                 // FIXME : not implemented
855                                 // throw new NotImplementedException ();
856                                 break;
857                         case "POOLING" :
858                                 pooling = ConvertToBoolean("pooling", value);
859                                 break;
860                         case "UID" :
861                         case "USER" :
862                         case "USER ID" :
863                                 parms.User = value;
864                                 break;
865                         case "WSID" :
866                         case "WORKSTATION ID" :
867                                 parms.Hostname = value;
868                                 break;
869                                 
870                         case "USER INSTANCE":
871                                 userInstance = ConvertToBoolean ("user instance", value);
872                                 break;
873                         default :
874                                 throw new ArgumentException("Keyword not supported :"+name);
875                         }
876                 }
877
878                 static bool IsValidDatabaseName (string database)
879                 {
880                         if ( database == null || database.Trim().Length == 0 || database.Length > 128)
881                                 return false ;
882                         
883                         if (database[0] == '"' && database[database.Length] == '"')
884                                 database = database.Substring (1, database.Length - 2);
885                         else if (Char.IsDigit (database[0]))
886                                 return false;
887
888                         if (database[0] == '_')
889                                 return false;
890
891                         foreach (char c  in database.Substring (1, database.Length - 1))
892                                 if (!Char.IsLetterOrDigit (c) && c != '_' && c != '-')
893                                         return false;
894                         return true;
895                 }
896
897                 private void OnSqlInfoMessage (SqlInfoMessageEventArgs value)
898                 {
899                         if (InfoMessage != null)
900                                 InfoMessage (this, value);
901                 }
902
903 #if !NET_2_0
904                 private new void OnStateChange (StateChangeEventArgs value)
905                 {
906                         if (StateChange != null)
907                                 StateChange (this, value);
908                 }
909 #endif
910
911                 private sealed class SqlMonitorSocket : UdpClient
912                 {
913                         // UDP port that the SQL Monitor listens
914                         private static readonly int SqlMonitorUdpPort = 1434;
915                         //private static readonly string SqlServerNotExist = "SQL Server does not exist or access denied";
916
917                         private string server;
918                         private string instance;
919
920                         internal SqlMonitorSocket (string ServerName, string InstanceName) 
921                                 : base (ServerName, SqlMonitorUdpPort) 
922                         {
923                                 server = ServerName;
924                                 instance = InstanceName;
925                         }
926
927                         internal int DiscoverTcpPort (int timeoutSeconds)
928                         {
929                                 int SqlServerTcpPort;
930                                 Client.Blocking = false;
931                                 // send command to UDP 1434 (SQL Monitor) to get
932                                 // the TCP port to connect to the MS SQL server
933                                 ASCIIEncoding enc = new ASCIIEncoding ();
934                                 Byte[] rawrq = new Byte [instance.Length + 1];
935                                 rawrq[0] = 4;
936                                 enc.GetBytes (instance, 0, instance.Length, rawrq, 1);
937                                 int bytes = Send (rawrq, rawrq.Length);
938
939                                 if (!Active)
940                                         return -1; // Error
941                                 
942                                 bool result;
943                                 long timeout = timeoutSeconds * 1000000;
944                                 result = Client.Poll ((int)timeout, SelectMode.SelectRead);
945                                 if (result == false)
946                                         return -1; // Error
947
948                                 if (Client.Available <= 0)
949                                         return -1; // Error
950 #if NET_2_0
951                                 IPEndPoint endpoint = new IPEndPoint (Dns.GetHostEntry ("localhost").AddressList [0], 0);
952 #else
953                                 IPEndPoint endpoint = new IPEndPoint (Dns.GetHostByName ("localhost").AddressList [0], 0);
954 #endif
955                                 Byte [] rawrs;
956
957                                 rawrs = Receive (ref endpoint);
958
959                                 string rs = Encoding.ASCII.GetString (rawrs);
960
961                                 string[] rawtokens = rs.Split (';');
962                                 Hashtable data = new Hashtable ();
963                                 for (int i = 0; i < rawtokens.Length / 2 && i < 256; i++) {
964                                         data [rawtokens [i * 2]] = rawtokens [ i * 2 + 1];
965                                 }
966
967                                 if (!data.ContainsKey ("tcp")) {
968                                         string msg = "Mono does not support names pipes or shared memory "
969                                                 + "for connecting to SQL Server. Please enable the TCP/IP "
970                                                 + "protocol.";
971                                         throw new NotImplementedException (msg);
972                                 }
973
974                                 SqlServerTcpPort = int.Parse ((string) data ["tcp"]);
975                                 Close ();
976
977                                 return SqlServerTcpPort;
978                         }
979                 }
980
981 #if NET_2_0
982                 struct ColumnInfo
983                 {
984                         public string name;
985                         public Type type;
986
987                         public ColumnInfo (string name, Type type)
988                         {
989                                 this.name = name; this.type = type;
990                         }
991                 }
992
993                 static class ReservedWords
994                 {
995                         static readonly string [] reservedWords =
996                         {
997                                 "ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER",
998                                   "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY",
999                                   "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE",
1000                                   "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC",
1001                                   "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ",
1002                                   "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE",
1003                                   "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK",
1004                                   "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE",
1005                                   "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN",
1006                                   "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT",
1007                                   "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY",
1008                                   "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL",
1009                                   "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE",
1010                                   "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT",
1011                                   "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT",
1012                                   "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE",
1013                                   "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE",
1014                                   "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER",
1015                                   "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT",
1016                                   "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN",
1017                                   "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD",
1018                                   "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK",
1019                                   "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER",
1020                                   "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL",
1021                                   "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF",
1022                                   "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS",
1023                                   "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN",
1024                                   "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE",
1025                                   "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW",
1026                                   "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN",
1027                                   "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL",
1028                                   "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT", "ABSOLUTE",
1029                                   "FOUND", "PRESERVE", "ACTION", "FREE", "PRIOR", "ADMIN",
1030                                   "GENERAL", "PRIVILEGES", "AFTER", "GET", "READS",
1031                                   "AGGREGATE", "GLOBAL", "REAL", "ALIAS", "GO", "RECURSIVE",
1032                                   "ALLOCATE", "GROUPING", "REF", "ARE", "HOST", "REFERENCING",
1033                                   "ARRAY", "HOUR", "RELATIVE", "ASSERTION", "IGNORE", "RESULT",
1034                                   "AT", "IMMEDIATE", "RETURNS", "BEFORE", "INDICATOR", "ROLE",
1035                                   "BINARY", "INITIALIZE", "ROLLUP", "BIT", "INITIALLY",
1036                                   "ROUTINE", "BLOB", "INOUT", "ROW", "BOOLEAN", "INPUT",
1037                                   "ROWS", "BOTH", "INT", "SAVEPOINT", "BREADTH", "INTEGER",
1038                                   "SCROLL", "CALL", "INTERVAL", "SCOPE", "CASCADED",
1039                                   "ISOLATION", "SEARCH", "CAST", "ITERATE", "SECOND",
1040                                   "CATALOG", "LANGUAGE", "SECTION", "CHAR", "LARGE",
1041                                   "SEQUENCE", "CHARACTER", "LAST", "SESSION", "CLASS",
1042                                   "LATERAL", "SETS", "CLOB", "LEADING", "SIZE", "COLLATION",
1043                                   "LESS", "SMALLINT", "COMPLETION", "LEVEL", "SPACE",
1044                                   "CONNECT", "LIMIT", "SPECIFIC", "CONNECTION", "LOCAL",
1045                                   "SPECIFICTYPE", "CONSTRAINTS", "LOCALTIME", "SQL",
1046                                   "CONSTRUCTOR", "LOCALTIMESTAMP", "SQLEXCEPTION",
1047                                   "CORRESPONDING", "LOCATOR", "SQLSTATE", "CUBE", "MAP",
1048                                   "SQLWARNING", "CURRENT_PATH", "MATCH", "START",
1049                                   "CURRENT_ROLE", "MINUTE", "STATE", "CYCLE", "MODIFIES",
1050                                   "STATEMENT", "DATA", "MODIFY", "STATIC", "DATE", "MODULE",
1051                                   "STRUCTURE", "DAY", "MONTH", "TEMPORARY", "DEC", "NAMES",
1052                                   "TERMINATE", "DECIMAL", "NATURAL", "THAN", "DEFERRABLE",
1053                                   "NCHAR", "TIME", "DEFERRED", "NCLOB", "TIMESTAMP", "DEPTH",
1054                                   "NEW", "TIMEZONE_HOUR", "DEREF", "NEXT", "TIMEZONE_MINUTE",
1055                                   "DESCRIBE", "NO", "TRAILING", "DESCRIPTOR", "NONE",
1056                                   "TRANSLATION", "DESTROY", "NUMERIC", "TREAT", "DESTRUCTOR",
1057                                   "OBJECT", "TRUE", "DETERMINISTIC", "OLD", "UNDER",
1058                                   "DICTIONARY", "ONLY", "UNKNOWN", "DIAGNOSTICS", "OPERATION",
1059                                   "UNNEST", "DISCONNECT", "ORDINALITY", "USAGE", "DOMAIN",
1060                                   "OUT", "USING", "DYNAMIC", "OUTPUT", "VALUE", "EACH",
1061                                   "PAD", "VARCHAR", "END-EXEC", "PARAMETER", "VARIABLE",
1062                                   "EQUALS", "PARAMETERS", "WHENEVER", "EVERY", "PARTIAL",
1063                                   "WITHOUT", "EXCEPTION", "PATH", "WORK", "EXTERNAL",
1064                                   "POSTFIX", "WRITE", "FALSE", "PREFIX", "YEAR", "FIRST",
1065                                   "PREORDER", "ZONE", "FLOAT", "PREPARE", "ADA", "AVG",
1066                                   "BIT_LENGTH", "CHAR_LENGTH", "CHARACTER_LENGTH", "COUNT",
1067                                   "EXTRACT", "FORTRAN", "INCLUDE", "INSENSITIVE", "LOWER",
1068                                   "MAX", "MIN", "OCTET_LENGTH", "OVERLAPS", "PASCAL",
1069                                   "POSITION", "SQLCA", "SQLCODE", "SQLERROR", "SUBSTRING",
1070                                   "SUM", "TRANSLATE", "TRIM", "UPPER"
1071                         };
1072                         static DataTable instance;
1073                         static public DataTable Instance {
1074                                 get {
1075                                         if (instance == null) {
1076                                                 DataRow row = null;
1077                                                 instance = new DataTable ("ReservedWords");
1078                                                 instance.Columns.Add ("ReservedWord", typeof(string));
1079                                                 foreach (string reservedWord in reservedWords)
1080                                                 {
1081                                                         row = instance.NewRow();
1082
1083                                                         row["ReservedWord"] = reservedWord;
1084                                                         instance.Rows.Add(row);
1085                                                 }
1086                                         }
1087                                         return instance;
1088                                 }
1089                         }
1090                 }
1091
1092                 static class MetaDataCollections
1093                 {
1094                         static readonly ColumnInfo [] columns = {
1095                                 new ColumnInfo ("CollectionName", typeof (string)),
1096                                 new ColumnInfo ("NumberOfRestrictions", typeof (int)),
1097                                 new ColumnInfo ("NumberOfIdentifierParts", typeof (int))
1098                         };
1099
1100                         static readonly object [][] rows = {
1101                                 new object [] {"MetaDataCollections", 0, 0},
1102                                 new object [] {"DataSourceInformation", 0, 0},
1103                                 new object [] {"DataTypes", 0, 0},
1104                                 new object [] {"Restrictions", 0, 0},
1105                                 new object [] {"ReservedWords", 0, 0},
1106                                 new object [] {"Users", 1, 1},
1107                                 new object [] {"Databases", 1, 1},
1108                                 new object [] {"Tables", 4, 3},
1109                                 new object [] {"Columns", 4, 4},
1110                                 new object [] {"StructuredTypeMembers", 4, 4},
1111                                 new object [] {"Views", 3, 3},
1112                                 new object [] {"ViewColumns", 4, 4},
1113                                 new object [] {"ProcedureParameters", 4, 1},
1114                                 new object [] {"Procedures", 4, 3},
1115                                 new object [] {"ForeignKeys", 4, 3},
1116                                 new object [] {"IndexColumns", 5, 4},
1117                                 new object [] {"Indexes", 4, 3},
1118                                 new object [] {"UserDefinedTypes", 2, 1}
1119                         };
1120
1121                         static DataTable instance;
1122                         static public DataTable Instance {
1123                                 get {
1124                                         if (instance == null) {
1125                                                 instance = new DataTable ("MetaDataCollections");
1126                                                 foreach (ColumnInfo c in columns)
1127                                                         instance.Columns.Add (c.name, c.type);
1128                                                 foreach (object [] row in rows)
1129                                                         instance.LoadDataRow (row, true);
1130                                         }
1131                                         return instance;
1132                                 }
1133                         }
1134                 }
1135
1136                 static class DataSourceInformation
1137                 {
1138                         static readonly ColumnInfo [] columns = {
1139                                 new ColumnInfo ("CompositeIdentifierSeparatorPattern", typeof (string)),
1140                                 new ColumnInfo ("DataSourceProductName", typeof(string)),
1141                                 new ColumnInfo ("DataSourceProductVersion", typeof(string)),
1142                                 new ColumnInfo ("DataSourceProductVersionNormalized", typeof(string)),
1143                                 new ColumnInfo ("GroupByBehavior", typeof(GroupByBehavior)),
1144                                 new ColumnInfo ("IdentifierPattern", typeof(string)),
1145                                 new ColumnInfo ("IdentifierCase", typeof(IdentifierCase)),
1146                                 new ColumnInfo ("OrderByColumnsInSelect", typeof(bool)),
1147                                 new ColumnInfo ("ParameterMarkerFormat", typeof(string)),
1148                                 new ColumnInfo ("ParameterMarkerPattern", typeof(string)),
1149                                 new ColumnInfo ("ParameterNameMaxLength", typeof(int)),
1150                                 new ColumnInfo ("ParameterNamePattern", typeof(string)),
1151                                 new ColumnInfo ("QuotedIdentifierPattern", typeof(string)),
1152                                 new ColumnInfo ("QuotedIdentifierCase", typeof(IdentifierCase)),
1153                                 new ColumnInfo ("StatementSeparatorPattern", typeof(string)),
1154                                 new ColumnInfo ("StringLiteralPattern", typeof(string)),
1155                                 new ColumnInfo ("SupportedJoinOperators", typeof(SupportedJoinOperators))
1156                         };
1157
1158                         static public DataTable GetInstance (SqlConnection conn)
1159                         {
1160                                 DataTable table = new DataTable ("DataSourceInformation");
1161                                 foreach (ColumnInfo c in columns)
1162                                         table.Columns.Add (c.name, c.type);
1163                                 DataRow row = table.NewRow ();
1164                                 row [0] = "\\.";
1165                                 row [1] = "Microsoft SQL Server";
1166                                 row [2] = conn.ServerVersion;;
1167                                 row [3] = conn.ServerVersion;;
1168                                 row [4] = GroupByBehavior.Unrelated;
1169                                 row [5] = @"(^\[\p{Lo}\p{Lu}\p{Ll}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Nd}@$#_]*$)|(^\[[^\]\0]|\]\]+\]$)|(^\""[^\""\0]|\""\""+\""$)";
1170                                 row [6] = IdentifierCase.Insensitive; // FIXME: obtain this from SQL Server
1171                                 row [7] = false;
1172                                 row [8] = "{0}";
1173                                 row [9] = @"@[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)";
1174                                 row [10] = 128;
1175                                 row [11] = @"^[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_@#][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)";
1176                                 row [12] = @"(([^\[]|\]\])*)";
1177                                 row [13] = IdentifierCase.Insensitive;  // FIXME: obtain this from SQL Server
1178                                 row [14] =";";
1179                                 row [15] = "'(([^']|'')*)'";
1180                                 row [16] = (SupportedJoinOperators.FullOuter | SupportedJoinOperators.Inner |
1181                                         SupportedJoinOperators.LeftOuter | SupportedJoinOperators.RightOuter);
1182                                 table.Rows.Add (row);
1183                                 return table;
1184                         }
1185                 }
1186
1187                 static class DataTypes
1188                 {
1189                         static readonly ColumnInfo [] columns = {
1190                                 new ColumnInfo ("TypeName", typeof(string)),
1191                                 new ColumnInfo ("ProviderDbType", typeof(int)),
1192                                 new ColumnInfo ("ColumnSize", typeof(long)),
1193                                 new ColumnInfo ("CreateFormat", typeof(string)),
1194                                 new ColumnInfo ("CreateParameters", typeof(string)),
1195                                 new ColumnInfo ("DataType", typeof(string)),
1196                                 new ColumnInfo ("IsAutoIncrementable", typeof(bool)),
1197                                 new ColumnInfo ("IsBestMatch", typeof(bool)),
1198                                 new ColumnInfo ("IsCaseSensitive", typeof(bool)),
1199                                 new ColumnInfo ("IsFixedLength", typeof(bool)),
1200                                 new ColumnInfo ("IsFixedPrecisionScale", typeof(bool)),
1201                                 new ColumnInfo ("IsLong", typeof(bool)),
1202                                 new ColumnInfo ("IsNullable", typeof(bool)),
1203                                 new ColumnInfo ("IsSearchable", typeof(bool)),
1204                                 new ColumnInfo ("IsSearchableWithLike", typeof(bool)),
1205                                 new ColumnInfo ("IsUnsigned", typeof(bool)),
1206                                 new ColumnInfo ("MaximumScale", typeof(short)),
1207                                 new ColumnInfo ("MinimumScale", typeof(short)),
1208                                 new ColumnInfo ("IsConcurrencyType", typeof(bool)),
1209                                 new ColumnInfo ("IsLiteralSupported", typeof(bool)),
1210                                 new ColumnInfo ("LiteralPrefix", typeof(string)),
1211                                 new ColumnInfo ("LiteralSuffix", typeof(string))
1212                         };
1213
1214                         static readonly object [][] rows = {
1215                                 new object [] {"smallint", 16, 5, "smallint", null, "System.Int16", true, true,
1216                                                false, true, true, false, true, true, false, false, null,
1217                                                null, false, null, null, null},
1218                                 new object [] {"int", 8, 10, "int", null, "System.Int32",
1219                                                true, true, false, true, true, false, true, true, false,
1220                                                false, null, null, false, null, null, null},
1221                                 new object [] {"real", 13, 7, "real", null,
1222                                                "System.Single", false, true, false, true, false, false,
1223                                                true, true, false, false, null, null, false, null, null, null},
1224                                 new object [] {"float", 6, 53, "float({0})",
1225                                                "number of bits used to store the mantissa", "System.Double",
1226                                                false, true, false, true, false, false, true, true,
1227                                                false, false, null, null, false, null, null, null},
1228                                 new object [] {"money", 9, 19, "money", null,
1229                                                "System.Decimal", false, false, false, true, true,
1230                                                false, true, true, false, false, null, null, false,
1231                                                null, null, null},
1232                                 new object [] {"smallmoney", 17, 10, "smallmoney", null,
1233                                                "System.Decimal", false, false, false, true, true, false,
1234                                                true, true, false, false, null, null, false, null, null, null},
1235                                 new object [] {"bit", 2, 1, "bit", null, "System.Boolean",
1236                                                false, false, false, true, false, false, true, true,
1237                                                false, null, null, null, false, null, null, null},
1238                                 new object [] {"tinyint", 20, 3, "tinyint", null,
1239                                                "System.SByte", true, true, false, true, true, false,
1240                                                true, true, false, true, null, null, false, null, null, null},
1241                                 new object [] {"bigint", 0, 19, "bigint", null,
1242                                                "System.Int64", true, true, false, true, true, false,
1243                                                true, true, false, false, null, null, false, null, null, null},
1244                                 new object [] {"timestamp", 19, 8, "timestamp", null,
1245                                                "System.Byte[]", false, false, false, true, false, false,
1246                                                false, true, false, null, null, null, true, null, "0x", null},
1247                                 new object [] {"binary", 1, 8000, "binary({0})", "length",
1248                                                "System.Byte[]", false, true, false, true, false, false,
1249                                                true, true, false, null, null, null, false, null, "0x", null},
1250                                 new object [] {"image", 7, 2147483647, "image", null,
1251                                                "System.Byte[]", false, true, false, false, false, true,
1252                                                true, false, false, null, null, null, false, null, "0x", null},
1253                                 new object [] {"text", 18, 2147483647, "text", null,
1254                                                "System.String", false, true, false, false, false, true,
1255                                                true, false, true, null, null, null, false, null, "'", "'"},
1256                                 new object [] {"ntext", 11, 1073741823, "ntext", null,
1257                                                "System.String", false, true, false, false, false, true,
1258                                                true, false, true, null, null, null, false, null, "N'", "'"},
1259                                 new object [] {"decimal", 5, 38, "decimal({0}, {1})",
1260                                                "precision,scale", "System.Decimal", true, true, false,
1261                                                true, false, false, true, true, false, false, 38, 0,
1262                                                false, null, null, null},
1263                                 new object [] {"numeric", 5, 38, "numeric({0}, {1})",
1264                                                "precision,scale", "System.Decimal", true, true, false,
1265                                                true, false, false, true, true, false, false, 38, 0,
1266                                                false, null, null, null},
1267                                 new object [] {"datetime", 4, 23, "datetime", null,
1268                                                "System.DateTime", false, true, false, true, false, false,
1269                                                true, true, true, null, null, null, false, null, "{ts '", "'}"},
1270                                 new object [] {"smalldatetime", 15, 16, "smalldatetime", null,
1271                                                "System.DateTime", false, true, false, true, false, false,
1272                                                true, true, true, null, null, null, false, null, "{ts '", "'}"},
1273                                 new object [] {"sql_variant", 23, null, "sql_variant",
1274                                                null, "System.Object", false, true, false, false, false,
1275                                                false, true, true, false, null, null, null, false, false,
1276                                                null, null},
1277                                 new object [] {"xml", 25, 2147483647, "xml", null,
1278                                                "System.String", false, false, false, false, false, true,
1279                                                true, false, false, null, null, null, false, false, null, null},
1280                                 new object [] {"varchar", 22, 2147483647, "varchar({0})",
1281                                                "max length", "System.String", false, true, false, false,
1282                                                false, false, true, true, true, null, null, null, false,
1283                                                null, "'", "'"},
1284                                 new object [] {"char", 3, 2147483647, "char({0})", "length",
1285                                                "System.String", false, true, false, true, false, false,
1286                                                true, true, true, null, null, null, false, null, "'", "'"},
1287                                 new object [] {"nchar", 10, 1073741823, "nchar({0})", "length",
1288                                                "System.String", false, true, false, true, false, false,
1289                                                true, true, true, null, null, null, false, null, "N'", "'"},
1290                                 new object [] {"nvarchar", 12, 1073741823, "nvarchar({0})", "max length",
1291                                                "System.String", false, true, false, false, false, false, true, true,
1292                                                true, null, null, null, false, null, "N'", "'"},
1293                                 new object [] {"varbinary", 21, 1073741823, "varbinary({0})",
1294                                                "max length", "System.Byte[]", false, true, false, false,
1295                                                false, false, true, true, false, null, null, null, false,
1296                                                null, "0x", null},
1297                                 new object [] {"uniqueidentifier", 14, 16, "uniqueidentifier", null,
1298                                                "System.Guid", false, true, false, true, false, false, true,
1299                                                true, false, null, null, null, false, null, "'", "'"},
1300                                 new object [] {"date", 31, 3L, "date", DBNull.Value,
1301                                                "System.DateTime", false, false, false, true, true, false,
1302                                                true, true, true, DBNull.Value, DBNull.Value, DBNull.Value,
1303                                                false, DBNull.Value, "{ts '", "'}"},
1304                                 new object [] {"time", 32, 5L, "time({0})", "scale",
1305                                                "System.TimeSpan", false, false, false, false, false, false,
1306                                                true, true, true, DBNull.Value, (short) 7, (short) 0,
1307                                                false, DBNull.Value, "{ts '", "'}"},
1308                                 new object [] {"datetime2", 33, 8L, "datetime2({0})", "scale",
1309                                                "System.DateTime", false, true, false, false, false, false,
1310                                                true, true, true, DBNull.Value, (short) 7, (short) 0,
1311                                                false, DBNull.Value, "{ts '", "'}"},
1312                                 new object [] {"datetimeoffset", 34, 10L, "datetimeoffset({0})",
1313                                                "scale", "System.DateTimeOffset", false, true, false, false,
1314                                                false, false, true, true, true, DBNull.Value, (short) 7, (short) 0,
1315                                                false, DBNull.Value, "{ts '", "'}"}
1316                         };
1317
1318                         static DataTable instance;
1319                         static public DataTable Instance {
1320                                 get {
1321                                         if (instance == null) {
1322                                                 instance = new DataTable ("DataTypes");
1323                                                 foreach (ColumnInfo c in columns)
1324                                                         instance.Columns.Add (c.name, c.type);
1325                                                 foreach (object [] row in rows)
1326                                                         instance.LoadDataRow (row, true);
1327                                         }
1328                                         return instance;
1329                                 }
1330                         }
1331                 }
1332
1333                 static class Restrictions
1334                 {
1335                         static readonly ColumnInfo [] columns = {
1336                                 new ColumnInfo ("CollectionName", typeof (string)),
1337                                 new ColumnInfo ("RestrictionName", typeof(string)),
1338                                 new ColumnInfo ("ParameterName", typeof(string)),
1339                                 new ColumnInfo ("RestrictionDefault", typeof(string)),
1340                                 new ColumnInfo ("RestrictionNumber", typeof(int))
1341                         };
1342
1343                         static readonly object [][] rows = {
1344                                 new object [] {"Users", "User_Name", "@Name", "name", 1},
1345                                 new object [] {"Databases", "Name", "@Name", "Name", 1},
1346
1347                                 new object [] {"Tables", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
1348                                 new object [] {"Tables", "Owner", "@Owner", "TABLE_SCHEMA", 2},
1349                                 new object [] {"Tables", "Table", "@Name", "TABLE_NAME", 3},
1350                                 new object [] {"Tables", "TableType", "@TableType", "TABLE_TYPE", 4},
1351
1352                                 new object [] {"Columns", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
1353                                 new object [] {"Columns", "Owner", "@Owner", "TABLE_SCHEMA", 2},
1354                                 new object [] {"Columns", "Table", "@Table", "TABLE_NAME", 3},
1355                                 new object [] {"Columns", "Column", "@Column", "COLUMN_NAME", 4},
1356
1357                                 new object [] {"StructuredTypeMembers", "Catalog", "@Catalog", "TYPE_CATALOG", 1},
1358                                 new object [] {"StructuredTypeMembers", "Owner", "@Owner", "TYPE_SCHEMA", 2},
1359                                 new object [] {"StructuredTypeMembers", "Type", "@Type", "TYPE_NAME", 3},
1360                                 new object [] {"StructuredTypeMembers", "Member", "@Member", "MEMBER_NAME", 4},
1361
1362                                 new object [] {"Views", "Catalog", "@Catalog", "TABLE_CATALOG", 1},
1363                                 new object [] {"Views", "Owner", "@Owner", "TABLE_SCHEMA", 2},
1364                                 new object [] {"Views", "Table", "@Table", "TABLE_NAME", 3},
1365
1366                                 new object [] {"ViewColumns", "Catalog", "@Catalog", "VIEW_CATALOG", 1},
1367                                 new object [] {"ViewColumns", "Owner", "@Owner", "VIEW_SCHEMA", 2},
1368                                 new object [] {"ViewColumns", "Table", "@Table", "VIEW_NAME", 3},
1369                                 new object [] {"ViewColumns", "Column", "@Column", "COLUMN_NAME", 4},
1370
1371                                 new object [] {"ProcedureParameters", "Catalog", "@Catalog", "SPECIFIC_CATALOG", 1},
1372                                 new object [] {"ProcedureParameters", "Owner", "@Owner", "SPECIFIC_SCHEMA", 2},
1373                                 new object [] {"ProcedureParameters", "Name", "@Name", "SPECIFIC_NAME", 3},
1374                                 new object [] {"ProcedureParameters", "Parameter", "@Parameter", "PARAMETER_NAME", 4},
1375
1376                                 new object [] {"Procedures", "Catalog", "@Catalog", "SPECIFIC_CATALOG", 1},
1377                                 new object [] {"Procedures", "Owner", "@Owner", "SPECIFIC_SCHEMA", 2},
1378                                 new object [] {"Procedures", "Name", "@Name", "SPECIFIC_NAME", 3},
1379                                 new object [] {"Procedures", "Type", "@Type", "ROUTINE_TYPE", 4},
1380
1381                                 new object [] {"IndexColumns", "Catalog", "@Catalog", "db_name()", 1},
1382                                 new object [] {"IndexColumns", "Owner", "@Owner", "user_name()", 2},
1383                                 new object [] {"IndexColumns", "Table", "@Table", "o.name", 3},
1384                                 new object [] {"IndexColumns", "ConstraintName", "@ConstraintName", "x.name", 4},
1385                                 new object [] {"IndexColumns", "Column", "@Column", "c.name", 5},
1386
1387                                 new object [] {"Indexes", "Catalog", "@Catalog", "db_name()", 1},
1388                                 new object [] {"Indexes", "Owner", "@Owner", "user_name()", 2},
1389                                 new object [] {"Indexes", "Table", "@Table", "o.name", 3},
1390                                 new object [] {"Indexes", "Name", "@Name", "x.name", 4},
1391
1392                                 new object [] {"UserDefinedTypes", "assembly_name", "@AssemblyName", "assemblies.name", 1},
1393                                 new object [] {"UserDefinedTypes", "udt_name", "@UDTName", "types.assembly_class", 2},
1394
1395                                 new object [] {"ForeignKeys", "Catalog", "@Catalog", "CONSTRAINT_CATALOG", 1},
1396                                 new object [] {"ForeignKeys", "Owner", "@Owner", "CONSTRAINT_SCHEMA", 2},
1397                                 new object [] {"ForeignKeys", "Table", "@Table", "TABLE_NAME", 3},
1398                                 new object [] {"ForeignKeys", "Name", "@Name", "CONSTRAINT_NAME", 4}
1399                         };
1400
1401                         static DataTable instance;
1402                         static public DataTable Instance {
1403                                 get {
1404                                         if (instance == null) {
1405                                                 instance = new DataTable ("Restrictions");
1406                                                 foreach (ColumnInfo c in columns)
1407                                                         instance.Columns.Add (c.name, c.type);
1408                                                 foreach (object [] row in rows)
1409                                                         instance.LoadDataRow (row, true);
1410                                         }
1411                                         return instance;
1412                                 }
1413                         }
1414                 }
1415
1416                 public override DataTable GetSchema ()
1417                 {
1418                         if (state == ConnectionState.Closed)
1419                                 throw ExceptionHelper.ConnectionClosed ();
1420
1421                         return MetaDataCollections.Instance;
1422                 }
1423
1424                 public override DataTable GetSchema (String collectionName)
1425                 {
1426                         return GetSchema (collectionName, null);
1427                 }
1428
1429                 public override DataTable GetSchema (String collectionName, string [] restrictionValues)
1430                 {
1431                         // LAMESPEC: In MS.NET, if collectionName is null, it throws ArgumentException.
1432
1433                         if (state == ConnectionState.Closed)
1434                                 throw ExceptionHelper.ConnectionClosed ();
1435
1436                         String cName = null;
1437                         DataTable schemaTable = MetaDataCollections.Instance;
1438                         int length = restrictionValues == null ? 0 : restrictionValues.Length;
1439
1440                         foreach (DataRow row in schemaTable.Rows) {
1441                                 if (String.Compare ((string) row["CollectionName"], collectionName, true) == 0) {
1442                                         if (length > (int) row["NumberOfRestrictions"]) {
1443                                                 throw new ArgumentException ("More restrictions were provided " +
1444                                                                              "than the requested schema ('" +
1445                                                                              row["CollectionName"].ToString () + "') supports");
1446                                         }
1447                                         cName = row["CollectionName"].ToString();
1448                                 }
1449                         }
1450
1451                         if (cName == null)
1452                                 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
1453                                         "The requested collection ({0}) is not defined.",
1454                                         collectionName));
1455
1456                         SqlCommand command     = null;
1457                         DataTable dataTable    = new DataTable ();
1458                         SqlDataAdapter dataAdapter = new SqlDataAdapter ();
1459
1460                         switch (cName)
1461                         {
1462                         case "Databases":
1463                                 command = new SqlCommand ("select name as database_name, dbid, crdate as create_date " +
1464                                                           "from master.sys.sysdatabases where (name = @Name or (@Name " +
1465                                                           "is null))", this);
1466                                 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1467                                 break;
1468                         case "ForeignKeys":
1469                                 command = new SqlCommand ("select CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME, " +
1470                                                           "TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_TYPE, " +
1471                                                           "IS_DEFERRABLE, INITIALLY_DEFERRED from " +
1472                                                           "INFORMATION_SCHEMA.TABLE_CONSTRAINTS where (CONSTRAINT_CATALOG" +
1473                                                           " = @Catalog or (@Catalog is null)) and (CONSTRAINT_SCHEMA = " +
1474                                                           "@Owner or (@Owner is null)) and (TABLE_NAME = @Table or (" +
1475                                                           "@Table is null)) and (CONSTRAINT_NAME = @Name or (@Name is null))" +
1476                                                           " and CONSTRAINT_TYPE = 'FOREIGN KEY' order by CONSTRAINT_CATALOG," +
1477                                                           " CONSTRAINT_SCHEMA, CONSTRAINT_NAME", this);
1478                                 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1479                                 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1480                                 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1481                                 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1482                                 break;
1483                         case "Indexes":
1484                                 command = new SqlCommand ("select distinct db_name() as constraint_catalog, " +
1485                                                           "constraint_schema = user_name (o.uid), " +
1486                                                           "constraint_name = x.name, table_catalog = db_name (), " +
1487                                                           "table_schema = user_name (o.uid), table_name = o.name, " +
1488                                                           "index_name  = x.name from sysobjects o, sysindexes x, " +
1489                                                           "sysindexkeys xk where o.type in ('U') and x.id = o.id and " +
1490                                                           "o.id = xk.id and x.indid = xk.indid and xk.keyno = x.keycnt " +
1491                                                           "and (db_name() = @Catalog or (@Catalog is null)) and " +
1492                                                           "(user_name() = @Owner or (@Owner is null)) and (o.name = " +
1493                                                           "@Table or (@Table is null)) and (x.name = @Name or (@Name is null))" +
1494                                                           "order by table_name, index_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);
1499                                 break;
1500                         case "IndexColumns":
1501                                 command = new SqlCommand ("select distinct db_name() as constraint_catalog, " +
1502                                                           "constraint_schema = user_name (o.uid), constraint_name = x.name, " +
1503                                                           "table_catalog = db_name (), table_schema = user_name (o.uid), " +
1504                                                           "table_name = o.name, column_name = c.name, " +
1505                                                           "ordinal_position = convert (int, xk.keyno), keyType = c.xtype, " +
1506                                                           "index_name = x.name from sysobjects o, sysindexes x, syscolumns c, " +
1507                                                           "sysindexkeys xk where o.type in ('U') and x.id = o.id and o.id = c.id " +
1508                                                           "and o.id = xk.id and x.indid = xk.indid and c.colid = xk.colid " +
1509                                                           "and xk.keyno <= x.keycnt and permissions (o.id, c.name) <> 0 " +
1510                                                           "and (db_name() = @Catalog or (@Catalog is null)) and (user_name() " +
1511                                                           "= @Owner or (@Owner is null)) and (o.name = @Table or (@Table is" +
1512                                                           " null)) and (x.name = @ConstraintName or (@ConstraintName is null)) " +
1513                                                           "and (c.name = @Column or (@Column is null)) order by table_name, " +
1514                                                           "index_name", this);
1515                                 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 8);
1516                                 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1517                                 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 13);
1518                                 command.Parameters.Add ("@ConstraintName", SqlDbType.NVarChar, 4000);
1519                                 command.Parameters.Add ("@Column", SqlDbType.NVarChar, 4000);
1520                                 break;
1521                         case "Procedures":
1522                                 command = new SqlCommand ("select SPECIFIC_CATALOG, SPECIFIC_SCHEMA, SPECIFIC_NAME, " +
1523                                                           "ROUTINE_CATALOG, ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE, " +
1524                                                           "CREATED, LAST_ALTERED from INFORMATION_SCHEMA.ROUTINES where " +
1525                                                           "(SPECIFIC_CATALOG = @Catalog or (@Catalog is null)) and " +
1526                                                           "(SPECIFIC_SCHEMA = @Owner or (@Owner is null)) and (SPECIFIC_NAME" +
1527                                                           " = @Name or (@Name is null)) and (ROUTINE_TYPE = @Type or (@Type " +
1528                                                           "is null)) order by SPECIFIC_CATALOG, SPECIFIC_SCHEMA, SPECIFIC_NAME", this);
1529                                 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1530                                 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1531                                 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1532                                 command.Parameters.Add ("@Type", SqlDbType.NVarChar, 4000);
1533                                 break;
1534                         case "ProcedureParameters":
1535                                 command = new SqlCommand ("select SPECIFIC_CATALOG, SPECIFIC_SCHEMA, SPECIFIC_NAME, " +
1536                                                           "ORDINAL_POSITION, PARAMETER_MODE, IS_RESULT, AS_LOCATOR, " +
1537                                                           "PARAMETER_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, " +
1538                                                           "CHARACTER_OCTET_LENGTH, COLLATION_CATALOG, COLLATION_SCHEMA, " +
1539                                                           "COLLATION_NAME, CHARACTER_SET_CATALOG, CHARACTER_SET_SCHEMA, " +
1540                                                           "CHARACTER_SET_NAME, NUMERIC_PRECISION, NUMERIC_PRECISION_RADIX, " +
1541                                                           "NUMERIC_SCALE, DATETIME_PRECISION, INTERVAL_TYPE, " +
1542                                                           "INTERVAL_PRECISION from INFORMATION_SCHEMA.PARAMETERS where " +
1543                                                           "(SPECIFIC_CATALOG = @Catalog or (@Catalog is null)) and " +
1544                                                           "(SPECIFIC_SCHEMA = @Owner or (@Owner is null)) and (SPECIFIC_NAME = " +
1545                                                           "@Name or (@Name is null)) and (PARAMETER_NAME = @Parameter or (" +
1546                                                           "@Parameter is null)) order by SPECIFIC_CATALOG, SPECIFIC_SCHEMA," +
1547                                                           " SPECIFIC_NAME, PARAMETER_NAME", this);
1548                                 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1549                                 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1550                                 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1551                                 command.Parameters.Add ("@Parameter", SqlDbType.NVarChar, 4000);
1552                                 break;
1553                         case "Tables":
1554                                 command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE " +
1555                                                           "from INFORMATION_SCHEMA.TABLES where" +
1556                                                           " (TABLE_CATALOG = @catalog or (@catalog is null)) and " +
1557                                                           "(TABLE_SCHEMA = @owner or (@owner is null))and " +
1558                                                           "(TABLE_NAME = @name or (@name is null)) and " +
1559                                                           "(TABLE_TYPE = @table_type or (@table_type is null))", this);
1560                                 command.Parameters.Add ("@catalog", SqlDbType.NVarChar, 8);
1561                                 command.Parameters.Add ("@owner", SqlDbType.NVarChar, 3);
1562                                 command.Parameters.Add ("@name", SqlDbType.NVarChar, 11);
1563                                 command.Parameters.Add ("@table_type", SqlDbType.NVarChar, 10);
1564                                 break;
1565                         case "Columns":
1566                                 command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, " +
1567                                                           "ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, " +
1568                                                           "CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH, " +
1569                                                           "NUMERIC_PRECISION, NUMERIC_PRECISION_RADIX, NUMERIC_SCALE, " +
1570                                                           "DATETIME_PRECISION, CHARACTER_SET_CATALOG, CHARACTER_SET_SCHEMA, " +
1571                                                           "CHARACTER_SET_NAME, COLLATION_CATALOG from INFORMATION_SCHEMA.COLUMNS" +
1572                                                           " where (TABLE_CATALOG = @Catalog or (@Catalog is null)) and (" +
1573                                                           "TABLE_SCHEMA = @Owner or (@Owner is null)) and (TABLE_NAME = @table" +
1574                                                           " or (@Table is null)) and (COLUMN_NAME = @column or (@Column is null" +
1575                                                           ")) order by TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME", this);
1576                                 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1577                                 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1578                                 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1579                                 command.Parameters.Add ("@Column", SqlDbType.NVarChar, 4000);
1580                                 break;
1581                         case "Users":
1582                                 command = new SqlCommand ("select uid, name as user_name, createdate, updatedate from sysusers" +
1583                                                           " where (name = @Name or (@Name is null))", this);
1584                                 command.Parameters.Add ("@Name", SqlDbType.NVarChar, 4000);
1585                                 break;
1586                         case "StructuredTypeMembers":
1587                                 // Only available on SQL Server 2008
1588                                 // Running it again SQL 2005 results in the following exception:
1589                                 // Unable to build the 'StructuredTypeMembers' collection because
1590                                 // execution of the SQL query failed. See the inner exception for details.
1591                                 // ---> System.Data.SqlClient.SqlException: Invalid object name 'sys.table_types'.
1592                                 // 
1593                                 // I don't have access to SQL Server 2008 right now,
1594                                 // and can't find any online documentation on the 'sys.table_types'
1595                                 // view
1596                                 throw new NotImplementedException ();
1597                         case "Views":
1598                                 command = new SqlCommand ("select TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, CHECK_OPTION, " +
1599                                                           "IS_UPDATABLE from INFORMATION_SCHEMA.VIEWS where (TABLE_CATALOG" +
1600                                                           " = @Catalog or (@Catalog is null)) TABLE_SCHEMA = @Owner or " +
1601                                                           "(@Owner is null)) and (TABLE_NAME = @table or (@Table is null))" +
1602                                                           " order by TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME", this);
1603                                 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1604                                 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1605                                 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1606                                 break;
1607                         case "ViewColumns":
1608                                 command = new SqlCommand ("select VIEW_CATALOG, VIEW_SCHEMA, VIEW_NAME, TABLE_CATALOG, " +
1609                                                           "TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from " +
1610                                                           "INFORMATION_SCHEMA.VIEW_COLUMN_USAGE where (VIEW_CATALOG = " +
1611                                                           "@Catalog (@Catalog is null)) and (VIEW_SCHEMA = @Owner (@Owner" +
1612                                                           " is null)) and (VIEW_NAME = @Table or (@Table is null)) and " +
1613                                                           "(COLUMN_NAME = @Column or (@Column is null)) order by " +
1614                                                           "VIEW_CATALOG, VIEW_SCHEMA, VIEW_NAME", this);
1615                                 command.Parameters.Add ("@Catalog", SqlDbType.NVarChar, 4000);
1616                                 command.Parameters.Add ("@Owner", SqlDbType.NVarChar, 4000);
1617                                 command.Parameters.Add ("@Table", SqlDbType.NVarChar, 4000);
1618                                 command.Parameters.Add ("@Column", SqlDbType.NVarChar, 4000);
1619                                 break;
1620                         case "UserDefinedTypes":
1621                                 command = new SqlCommand ("select assemblies.name as assembly_name, types.assembly_class " +
1622                                                           "as udt_name, ASSEMBLYPROPERTY(assemblies.name, 'VersionMajor') " +
1623                                                           "as version_major, ASSEMBLYPROPERTY(assemblies.name, 'VersionMinor') " +
1624                                                           "as version_minor, ASSEMBLYPROPERTY(assemblies.name, 'VersionBuild') " +
1625                                                           "as version_build, ASSEMBLYPROPERTY(assemblies.name, 'VersionRevision') " +
1626                                                           "as version_revision, ASSEMBLYPROPERTY(assemblies.name, 'CultureInfo') " +
1627                                                           "as culture_info, ASSEMBLYPROPERTY(assemblies.name, 'PublicKey') " +
1628                                                           "as public_key, is_fixed_length, max_length, Create_Date, " +
1629                                                           "Permission_set_desc from sys.assemblies as assemblies join " +
1630                                                           "sys.assembly_types as types on assemblies.assembly_id = types.assembly_id" +
1631                                                           " where (assportemblies.name = @AssemblyName or (@AssemblyName is null)) and " +
1632                                                           "(types.assembly_class = @UDTName or (@UDTName is null))",
1633                                                           this);
1634                                 command.Parameters.Add ("@AssemblyName", SqlDbType.NVarChar, 4000);
1635                                 command.Parameters.Add ("@UDTName", SqlDbType.NVarChar, 4000);
1636                                 break;
1637                         case "MetaDataCollections":
1638                                 return MetaDataCollections.Instance;
1639                         case "DataSourceInformation":
1640                                 return DataSourceInformation.GetInstance (this);
1641                         case "DataTypes":
1642                                 return DataTypes.Instance;
1643                         case "ReservedWords":
1644                                 return ReservedWords.Instance;
1645                         case "Restrictions":
1646                                 return Restrictions.Instance;
1647                         }
1648                         for (int i = 0; i < length; i++) {
1649                                 command.Parameters[i].Value = restrictionValues[i];
1650                         }
1651                         dataAdapter.SelectCommand = command;
1652                         dataAdapter.Fill (dataTable);
1653                         return dataTable;
1654                 }
1655                 
1656                 public static void ChangePassword (string connectionString, string newPassword)
1657                 {
1658                         if (connectionString == null || newPassword == null || newPassword == String.Empty)
1659                                 throw new ArgumentNullException ();
1660                         if (newPassword.Length > 128)
1661                                 throw new ArgumentException ("The value of newPassword exceeds its permittable length which is 128");
1662                         using (SqlConnection conn = new SqlConnection (connectionString)) {
1663                                 conn.Open ();
1664                                 conn.tds.Execute (String.Format ("sp_password '{0}', '{1}', '{2}'",
1665                                                                  conn.parms.Password, newPassword, conn.parms.User));
1666                         }
1667                 }
1668
1669                 public static void ClearAllPools ()
1670                 {
1671 #if NET_2_0
1672                         IDictionary <string, TdsConnectionPool> pools = SqlConnection.sqlConnectionPools.GetConnectionPool ();
1673 #else
1674                         Hashtable pools = SqlConnection.sqlConnectionPools.GetConnectionPool ();
1675 #endif
1676                         foreach (TdsConnectionPool pool in pools.Values) {
1677                                 if (pool != null) {
1678                                         pool.ResetConnectionPool ();
1679                                         Tds tds = pool.GetConnection ();
1680                                         tds.Pooling = false;
1681                                 }
1682                         }
1683                 }
1684
1685                 public static void ClearPool (SqlConnection connection)
1686                 {
1687                         if (connection.pooling) {
1688                                 connection.pooling = false;
1689                                 if (connection.pool != null)
1690                                         connection.pool.ResetConnectionPool (connection.Tds);
1691                         }
1692                 }
1693
1694 #endif // NET_2_0
1695
1696                 #endregion // Methods
1697
1698 #if NET_2_0
1699                 #region Fields Net 2
1700
1701                 bool async = false;
1702
1703                 #endregion // Fields  Net 2
1704
1705                 #region Properties Net 2
1706
1707 #if NET_1_0
1708                 [DataSysDescription ("Enable Asynchronous processing, 'Asynchrouse Processing=true/false' in the ConnectionString.")]   
1709 #endif
1710                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
1711                 internal bool AsyncProcessing  {
1712                         get { return async; }
1713                 }
1714
1715                 #endregion // Properties Net 2
1716
1717 #endif // NET_2_0
1718
1719         }
1720 }