Переглянути джерело

2002-11-07 Tim Coleman <[email protected]>
* System.Data.Common/DbDataAdapter.cs:
Remove NotImplementedException in Dispose
* System.Data.Common/FieldNameLookup.cs:
Should be sealed
* System.Data.SqlClient/SqlCommand.cs:
Fix CommandText accessor (stack overflow)
Implement DeriveParameters method
* System.Data.SqlClient/SqlCommandBuilder.cs:
Implement this class
* System.Data.SqlClient/SqlConnection.cs:
Change application name to "Mono SqlClient Data Provider"
* System.Data.SqlClient/SqlDataReader.cs:
Add new schema information
* System.Data.SqlClient/SqlError.cs:
* System.Data.SqlClient/SqlErrorCollection.cs:
Remove internal methods, TODO attributes
* System.Data.SqlClient/SqlParameter.cs:
Add new internal constructor for DeriveParameters use
* System.Data.SqlClient/SqlParameterConverter.cs:
Add missing methods based on class status

svn path=/trunk/mcs/; revision=8864

Tim Coleman 23 роки тому
батько
коміт
ce80d58963

+ 22 - 0
mcs/class/System.Data/ChangeLog

@@ -1,3 +1,25 @@
+2002-11-07  Tim Coleman <[email protected]>
+	* System.Data.Common/DbDataAdapter.cs:
+		Remove NotImplementedException in Dispose
+	* System.Data.Common/FieldNameLookup.cs:
+		Should be sealed
+	* System.Data.SqlClient/SqlCommand.cs:
+		Fix CommandText accessor (stack overflow)
+		Implement DeriveParameters method
+	* System.Data.SqlClient/SqlCommandBuilder.cs:
+		Implement this class
+	* System.Data.SqlClient/SqlConnection.cs:
+		Change application name to "Mono SqlClient Data Provider"
+	* System.Data.SqlClient/SqlDataReader.cs:
+		Add new schema information
+	* System.Data.SqlClient/SqlError.cs:
+	* System.Data.SqlClient/SqlErrorCollection.cs:
+		Remove internal methods, TODO attributes
+	* System.Data.SqlClient/SqlParameter.cs:
+		Add new internal constructor for DeriveParameters use
+	* System.Data.SqlClient/SqlParameterConverter.cs:
+		Add missing methods based on class status
+
 2002-11-07  Nick Drochak <[email protected]>
 	* list: add System.Data/ColumnDataPropertyDescriptor.cs
 

+ 0 - 1
mcs/class/System.Data/System.Data.Common/DbDataAdapter.cs

@@ -62,7 +62,6 @@ namespace System.Data.Common
 		[MonoTODO]
 		protected override void Dispose (bool disposing)
 		{
-			throw new NotImplementedException ();
 		}
 
                 public override int Fill (DataSet dataSet)

+ 1 - 1
mcs/class/System.Data/System.Data.Common/FieldNameLookup.cs

@@ -11,7 +11,7 @@ using System.Collections;
 using System.Data;
 
 namespace System.Data.Common {
-	internal class FieldNameLookup : ICollection, IEnumerable
+	internal sealed class FieldNameLookup : ICollection, IEnumerable
 	{
 		#region Fields
 

+ 24 - 2
mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs

@@ -86,7 +86,7 @@ namespace System.Data.SqlClient {
 		[DefaultValue ("")]
 		[RefreshProperties (RefreshProperties.All)]
 		public string CommandText {
-			get { return CommandText; }
+			get { return commandText; }
 			set { commandText = value; }
 		}
 
@@ -317,7 +317,7 @@ namespace System.Data.SqlClient {
 				index += 1;
 			}
 
-			return String.Format ("{0}\n{1}exec {2} {3}\n{4}", declarations.ToString (), set.ToString (), procedure, parms.ToString (), outParms.ToString ());
+			return String.Format ("{0}\n{1}{2} {3}\n{4}", declarations.ToString (), set.ToString (), procedure, parms.ToString (), outParms.ToString ());
 		}
 
 		public void Cancel () 
@@ -341,6 +341,27 @@ namespace System.Data.SqlClient {
 			return new SqlParameter ();
 		}
 
+		internal void DeriveParameters ()
+		{
+			if (commandType != CommandType.StoredProcedure)
+				throw new InvalidOperationException (String.Format ("SqlCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
+			ValidateCommand ("DeriveParameters");
+
+			SqlParameterCollection localParameters = new SqlParameterCollection (this);
+			localParameters.Add ("@P1", SqlDbType.NVarChar, commandText.Length).Value = commandText;
+
+			connection.Tds.ExecuteQuery (BuildProcedureCall ("sp_procedure_params_rowset", localParameters));
+			SqlDataReader reader = new SqlDataReader (this);
+			parameters.Clear ();
+			object[] dbValues = new object[reader.FieldCount];
+
+			while (reader.Read ()) {
+				reader.GetValues (dbValues);
+				parameters.Add (new SqlParameter (dbValues));
+			}
+			reader.Close ();	
+		}
+
 		public int ExecuteNonQuery ()
 		{
 			ValidateCommand ("ExecuteNonQuery");
@@ -461,6 +482,7 @@ namespace System.Data.SqlClient {
 
 		void IDisposable.Dispose ()
 		{
+Console.WriteLine ("Disposing");
 			Dispose (true);
 		}
 

+ 351 - 49
mcs/class/System.Data/System.Data.SqlClient/SqlCommandBuilder.cs

@@ -1,128 +1,430 @@
 //
-// System.Data.SqlClient.SqlCommandBuilder.cs
+// System.Data.Common.CommandBuilder.cs
 //
 // Author:
-//   Rodrigo Moya ([email protected])
-//   Daniel Morgan ([email protected])
 //   Tim Coleman ([email protected])
 //
-// (C) Ximian, Inc 2002
 // Copyright (C) Tim Coleman, 2002
 //
 
 using System;
-using System.Data;
+using System.Collections;
 using System.ComponentModel;
+using System.Data;
+using System.Data.Common;
+using System.Text;
 
 namespace System.Data.SqlClient {
-	/// <summary>
-	/// Builder of one command
-	/// that will be used in manipulating a table for
-	/// a DataSet that is assoicated with a database.
-	/// </summary>
-	public sealed class SqlCommandBuilder : Component 
+	public sealed class SqlCommandBuilder : Component
 	{
 		#region Fields
 
+		DataTable dbSchemaTable;
+		SqlDataAdapter adapter;
 		string quotePrefix;
 		string quoteSuffix;
-		SqlDataAdapter adapter;
+		string[] columnNames;
+		string tableName;
+	
+		SqlCommand deleteCommand;
+		SqlCommand insertCommand;
+		SqlCommand updateCommand;
+
+		// Used to construct WHERE clauses
+		static readonly string clause1 = "({0} IS NULL AND {1} IS NULL)";
+		static readonly string clause2 = "({0} = {1})";
 
 		#endregion // Fields
 
 		#region Constructors
 
 		public SqlCommandBuilder () 
-			: this (null)
 		{
+			dbSchemaTable = null;
+			adapter = null;
+			quoteSuffix = String.Empty;
+			quotePrefix = String.Empty;
 		}
 
-		public SqlCommandBuilder (SqlDataAdapter adapter) 
+		public SqlCommandBuilder (SqlDataAdapter adapter)
+			: this ()
 		{
-			this.adapter = adapter;
-			this.quotePrefix = String.Empty;
-			this.quoteSuffix = String.Empty;
+			DataAdapter = adapter;
 		}
 
 		#endregion // Constructors
 
 		#region Properties
 
-		[DataSysDescription ("The DataAdapter for which to automatically generator SqlCommands.")]
-		[DefaultValue (null)]
 		public SqlDataAdapter DataAdapter {
 			get { return adapter; }
 			set { 
+				adapter = value; 
 				if (adapter != null)
-					adapter.RowUpdating -= new SqlRowUpdatingEventHandler (RowUpdatingHandler);
-				adapter = value;
-				adapter.RowUpdating += new SqlRowUpdatingEventHandler (RowUpdatingHandler);
+					adapter.RowUpdating += new SqlRowUpdatingEventHandler (RowUpdatingHandler);
 			}
 		}
 
-		[Browsable (false)]
-		[DataSysDescription ("The character used in a text command as the opening quote for quoting identifiers that contain special characters.")]
-		[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+		private string QuotedTableName {
+			get { return GetQuotedString (tableName); }
+		}
+
 		public string QuotePrefix {
 			get { return quotePrefix; }
-			set { quotePrefix = value; }
+			set { 
+				if (dbSchemaTable != null)
+					throw new InvalidOperationException ("The QuotePrefix and QuoteSuffix properties cannot be changed once an Insert, Update, or Delete command has been generated.");
+				quotePrefix = value; 
+			}
 		}
 
-		[Browsable (false)]
-		[DataSysDescription ("The character used in a text command as the closing quote for quoting identifiers that contain special characters.")]
-		[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
 		public string QuoteSuffix {
 			get { return quoteSuffix; }
-			set { quoteSuffix = value; }
+			set {
+				if (dbSchemaTable != null)
+					throw new InvalidOperationException ("The QuotePrefix and QuoteSuffix properties cannot be changed once an Insert, Update, or Delete command has been generated.");
+				quoteSuffix = value; 
+			}
+		}
+
+		private SqlCommand SourceCommand {
+			get {
+				if (adapter != null)
+					return adapter.SelectCommand;
+				return null;
+			}
 		}
 
 		#endregion // Properties
 
 		#region Methods
 
-		[MonoTODO]
-		public static void DeriveParameters (SqlCommand command) 
+		private void BuildCache (bool closeConnection)
+		{
+			SqlCommand sourceCommand = SourceCommand;
+			if (sourceCommand == null)
+				throw new InvalidOperationException ("The DataAdapter.SelectCommand property needs to be initialized.");
+			SqlConnection connection = sourceCommand.Connection;
+			if (connection == null)
+				throw new InvalidOperationException ("The DataAdapter.SelectCommand.Connection property needs to be initialized.");
+				
+			if (dbSchemaTable == null) {
+				if (connection.State == ConnectionState.Open)
+					closeConnection = false;	
+				else
+					connection.Open ();
+	
+				SqlDataReader reader = sourceCommand.ExecuteReader (CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo);
+				dbSchemaTable = reader.GetSchemaTable ();
+				if (closeConnection)
+					connection.Close ();	
+				BuildInformation (dbSchemaTable);
+			}
+		}
+		
+		private void BuildInformation (DataTable schemaTable)
 		{
-			throw new NotImplementedException ();
+			tableName = String.Empty;
+			foreach (DataRow schemaRow in schemaTable.Rows) {
+				if (tableName == String.Empty) 
+					tableName = (string) schemaRow ["BaseTableName"];
+				if (tableName != (string) schemaRow["BaseTableName"])
+					throw new InvalidOperationException ("Dynamic SQL generation is not supported against multiple base tables.");
+			}
+			dbSchemaTable = schemaTable;
 		}
 
-		[MonoTODO]
-		public SqlCommand GetDeleteCommand () 
+		private SqlCommand CreateDeleteCommand (DataRow row, DataTableMapping tableMapping) 
 		{
-			throw new NotImplementedException ();
+			// If no table was found, then we can't do an delete
+			if (QuotedTableName == String.Empty)
+				return null;
+
+			CreateNewCommand (ref deleteCommand);
+
+			string command = String.Format ("DELETE FROM {0} ", QuotedTableName);
+			StringBuilder columns = new StringBuilder ();
+			StringBuilder where = new StringBuilder ();
+
+			int parmIndex = 1;
+
+			foreach (DataRow schemaRow in dbSchemaTable.Rows) {
+				if (!IncludedInWhereClause (schemaRow)) 
+					continue;
+
+				if (where.Length > 0) 
+					where.Append (" AND ");
+
+				bool isKey = (bool) schemaRow ["IsKey"];
+				SqlParameter parameter = null;
+
+				if (!isKey) {
+					parameter = deleteCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
+					where.Append ("(");
+					where.Append (String.Format (clause1, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
+					where.Append (" OR ");
+				}
+					
+				parameter = deleteCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
+				if (row != null)
+					parameter.Value = row [parameter.SourceColumn, DataRowVersion.Current];
+				where.Append (String.Format (clause2, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
+
+				if (!isKey)
+					where.Append (")");
+			}
+
+			// We're all done, so bring it on home
+			string sql = String.Format ("{0} WHERE ( {1} )", command, where.ToString ());
+			deleteCommand.CommandText = sql;
+			return deleteCommand;
 		}
 
-		[MonoTODO]
-		public SqlCommand GetInsertCommand () 
+		private SqlCommand CreateInsertCommand (DataRow row, DataTableMapping tableMapping) 
 		{
-			throw new NotImplementedException ();
+			if (QuotedTableName == String.Empty)
+				return null;
+
+			CreateNewCommand (ref insertCommand);
+
+			string command = String.Format ("INSERT INTO {0}", QuotedTableName);
+			string sql;
+			StringBuilder columns = new StringBuilder ();
+			StringBuilder values = new StringBuilder ();
+
+			int parmIndex = 1;
+			foreach (DataRow schemaRow in dbSchemaTable.Rows) {
+				if (!IncludedInInsert (schemaRow))
+					continue;
+
+				if (parmIndex > 1) {
+					columns.Append (" , ");
+					values.Append (" , ");
+				}
+
+				SqlParameter parameter = insertCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
+				if (row != null)
+					parameter.Value = row [parameter.SourceColumn, DataRowVersion.Proposed];
+				columns.Append (GetQuotedString (parameter.SourceColumn));
+				values.Append (parameter.ParameterName);
+			}
+
+			sql = String.Format ("{0}( {1} ) VALUES ( {2} )", command, columns.ToString (), values.ToString ());
+			insertCommand.CommandText = sql;
+			return insertCommand;
 		}
 
-		[MonoTODO]
-		public SqlCommand GetUpdateCommand () 
+		private void CreateNewCommand (ref SqlCommand command)
 		{
-			throw new NotImplementedException ();
+			SqlCommand sourceCommand = SourceCommand;
+			if (command == null) {
+				command = sourceCommand.Connection.CreateCommand ();
+				command.CommandTimeout = sourceCommand.CommandTimeout;
+				command.Transaction = sourceCommand.Transaction;
+			}
+			command.CommandType = CommandType.Text;
+			command.UpdatedRowSource = UpdateRowSource.None;
 		}
 
-		[MonoTODO]
-		public void RefreshSchema () 
+		private SqlCommand CreateUpdateCommand (DataRow row, DataTableMapping tableMapping) 
 		{
-			throw new NotImplementedException ();
+			// If no table was found, then we can't do an update
+			if (QuotedTableName == String.Empty)
+				return null;
+
+			CreateNewCommand (ref updateCommand);
+
+			string command = String.Format ("UPDATE {0} SET ", QuotedTableName);
+			StringBuilder columns = new StringBuilder ();
+			StringBuilder where = new StringBuilder ();
+
+			int parmIndex = 1;
+
+			// First, create the X=Y list for UPDATE
+			foreach (DataRow schemaRow in dbSchemaTable.Rows) {
+				if (columns.Length > 0) 
+					columns.Append (" , ");
+
+				SqlParameter parameter = updateCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
+				if (row != null)
+					parameter.Value = row [parameter.SourceColumn, DataRowVersion.Proposed];
+				columns.Append (String.Format ("{0} = {1}", GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
+			}
+
+			// Now, create the WHERE clause.  This may be optimizable, but it would be ugly to incorporate
+			// into the loop above.  "Premature optimization is the root of all evil." -- Knuth
+			foreach (DataRow schemaRow in dbSchemaTable.Rows) {
+				if (!IncludedInWhereClause (schemaRow)) 
+					continue;
+
+				if (where.Length > 0) 
+					where.Append (" AND ");
+
+				bool isKey = (bool) schemaRow ["IsKey"];
+				SqlParameter parameter = null;
+
+				if (!isKey) {
+					parameter = updateCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
+					where.Append ("(");
+					where.Append (String.Format (clause1, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
+					where.Append (" OR ");
+				}
+					
+				parameter = updateCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
+				if (row != null)
+					parameter.Value = row [parameter.SourceColumn, DataRowVersion.Current];
+				where.Append (String.Format (clause2, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
+
+				if (!isKey)
+					where.Append (")");
+			}
+
+			// We're all done, so bring it on home
+			string sql = String.Format ("{0}{1} WHERE ( {2} )", command, columns.ToString (), where.ToString ());
+			updateCommand.CommandText = sql;
+			return updateCommand;
+		}
+
+		private SqlParameter CreateParameter (int parmIndex, DataRow schemaRow)
+		{
+			string name = String.Format ("@p{0}", parmIndex);
+			string sourceColumn = (string) schemaRow ["BaseColumnName"];
+			SqlDbType sqlDbType = (SqlDbType) schemaRow ["ProviderType"];
+			int size = (int) schemaRow ["ColumnSize"];
+
+			return new SqlParameter (name, sqlDbType, size, sourceColumn);
+		}
+
+		public static void DeriveParameters (SqlCommand command)
+		{
+			command.DeriveParameters ();
 		}
 
 		[MonoTODO]
-		private void RowUpdatingHandler (object sender, SqlRowUpdatingEventArgs e)
+		protected override void Dispose (bool disposing)
+		{
+		}
+
+		public SqlCommand GetDeleteCommand ()
+		{
+			BuildCache (true);
+			return CreateDeleteCommand (null, null);
+		}
+
+		public SqlCommand GetInsertCommand ()
+		{
+			BuildCache (true);
+			return CreateInsertCommand (null, null);
+		}
+
+		private string GetQuotedString (string value)
+		{
+			if (value == String.Empty || value == null)
+				return value;
+			if (quotePrefix == String.Empty && quoteSuffix == String.Empty)
+				return value;
+			return String.Format ("{0}{1}{2}", quotePrefix, value, quoteSuffix);
+		}
+
+		public SqlCommand GetUpdateCommand ()
 		{
-			throw new NotImplementedException ();
+			BuildCache (true);
+			return CreateUpdateCommand (null, null);
+		}
+
+		private bool IncludedInInsert (DataRow schemaRow)
+		{
+			// If the parameter has one of these properties, then we don't include it in the insert:
+			// AutoIncrement, Hidden, Expression, RowVersion, ReadOnly
+
+			if ((bool) schemaRow ["IsAutoIncrement"])
+				return false;
+			if ((bool) schemaRow ["IsHidden"])
+				return false;
+			if ((bool) schemaRow ["IsExpression"])
+				return false;
+			if ((bool) schemaRow ["IsRowVersion"])
+				return false;
+			if ((bool) schemaRow ["IsReadOnly"])
+				return false;
+			return true;
+		}
+
+		private bool IncludedInUpdate (DataRow schemaRow)
+		{
+			// If the parameter has one of these properties, then we don't include it in the insert:
+			// AutoIncrement, Hidden, RowVersion
+
+			if ((bool) schemaRow ["IsAutoIncrement"])
+				return false;
+			if ((bool) schemaRow ["IsHidden"])
+				return false;
+			if ((bool) schemaRow ["IsRowVersion"])
+				return false;
+			return true;
+		}
+
+		private bool IncludedInWhereClause (DataRow schemaRow)
+		{
+			if ((bool) schemaRow ["IsLong"])
+				return false;
+			return true;
 		}
 
 		[MonoTODO]
-		protected override void Dispose (bool disposing) 
+		public void RefreshSchema () 
 		{
-			throw new NotImplementedException ();
+			tableName = String.Empty;
+			dbSchemaTable = null;
 		}
 
 		#endregion // Methods
+
+		#region Event Handlers
+
+		private void RowUpdatingHandler (object sender, SqlRowUpdatingEventArgs e)
+		{
+			if (e.Status != UpdateStatus.Continue)
+				return;
+
+			switch (e.StatementType) {
+			case StatementType.Delete:
+				deleteCommand = e.Command;
+				break;
+			case StatementType.Insert:
+				insertCommand = e.Command;
+				break;
+			case StatementType.Update:
+				updateCommand = e.Command;
+				break;
+			default:
+				return;
+			}
+
+			BuildCache (false);
+
+			switch (e.StatementType) {
+			case StatementType.Delete:
+				e.Command = CreateDeleteCommand (e.Row, e.TableMapping);
+				e.Status = UpdateStatus.Continue;
+				break;
+			case StatementType.Insert:
+				e.Command = CreateInsertCommand (e.Row, e.TableMapping);
+				e.Status = UpdateStatus.Continue;
+				break;
+			case StatementType.Update:
+				e.Command = CreateUpdateCommand (e.Row, e.TableMapping);
+				e.Status = UpdateStatus.Continue;
+				break;
+			}
+			
+			if (e.Command != null && e.Row != null) {
+				e.Row.AcceptChanges ();
+				e.Status = UpdateStatus.SkipCurrentRow;
+			}
+		}
+
+		#endregion // Event Handlers
 	}
 }
 

+ 1 - 1
mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs

@@ -390,7 +390,7 @@ namespace System.Data.SqlClient {
                 void SetDefaultConnectionParameters (NameValueCollection parameters)
                 {
                         if (null == parameters.Get ("APPLICATION NAME"))
-                                parameters["APPLICATION NAME"] = ".Net SqlClient Data Provider";
+                                parameters["APPLICATION NAME"] = "Mono SqlClient Data Provider";
                         if (null == parameters.Get ("CONNECT TIMEOUT") && null == parameters.Get ("CONNECTION TIMEOUT"))
                                 parameters["CONNECT TIMEOUT"] = "15";
                         if (null == parameters.Get ("CONNECTION LIFETIME"))

+ 21 - 10
mcs/class/System.Data/System.Data.SqlClient/SqlDataReader.cs

@@ -291,18 +291,34 @@ namespace System.Data.SqlClient {
 			foreach (TdsSchemaInfo schema in command.Tds.Schema) {
 				DataRow row = schemaTable.NewRow ();
 
+				// set default values
+				row ["AllowDBNull"] = true;
+				row ["BaseCatalogName"] = DBNull.Value;
+				row ["BaseColumnName"] = DBNull.Value;
+				row ["BaseSchemaName"] = DBNull.Value;
+				row ["BaseTableName"] = DBNull.Value;
+				row ["ColumnName"] = DBNull.Value;
+				row ["IsAutoIncrement"] = false;
+				row ["IsHidden"] = false;
+				row ["IsLong"] = false;
+				row ["IsRowVersion"] = false;
+				row ["IsUnique"] = false;
+				row ["NumericPrecision"] = DBNull.Value;
+				row ["NumericScale"] = DBNull.Value;
 
 				switch (schema.ColumnType) {
 					case TdsColumnType.Image :
 						dataTypeNames.Add ("image");
 						row ["ProviderType"] = (int) SqlDbType.Image;
 						row ["DataType"] = typeof (byte[]);
+						row ["IsLong"] = true;
 						break;
 					case TdsColumnType.Text :
 						dataTypes.Add (typeof (string));
 						dataTypeNames.Add ("text");
 						row ["ProviderType"] = (int) SqlDbType.Text;
 						row ["DataType"] = typeof (string);
+						row ["IsLong"] = true;
 						break;
 					case TdsColumnType.UniqueIdentifier :
 						dataTypeNames.Add ("uniqueidentifier");
@@ -314,6 +330,7 @@ namespace System.Data.SqlClient {
 						dataTypeNames.Add ("varbinary");
 						row ["ProviderType"] = (int) SqlDbType.VarBinary;
 						row ["DataType"] = typeof (byte[]);
+						row ["IsLong"] = true;
 						break;
 					case TdsColumnType.IntN :
 					case TdsColumnType.Int4 :
@@ -332,6 +349,7 @@ namespace System.Data.SqlClient {
 						dataTypeNames.Add ("binary");
 						row ["ProviderType"] = (int) SqlDbType.Binary;
 						row ["DataType"] = typeof (byte[]);
+						row ["IsLong"] = true;
 						break;
 					case TdsColumnType.Char :
 					case TdsColumnType.BigChar :
@@ -384,6 +402,7 @@ namespace System.Data.SqlClient {
 						dataTypeNames.Add ("ntext");
 						row ["ProviderType"] = (int) SqlDbType.NText;
 						row ["DataType"] = typeof (string);
+						row ["IsLong"] = true;
 						break;
 					case TdsColumnType.NVarChar :
 						dataTypeNames.Add ("nvarchar");
@@ -413,16 +432,6 @@ namespace System.Data.SqlClient {
 						break;
 				}
 
-				// set default values
-				row ["AllowDBNull"] = true;
-				row ["BaseCatalogName"] = DBNull.Value;
-				row ["BaseColumnName"] = DBNull.Value;
-				row ["BaseSchemaName"] = DBNull.Value;
-				row ["BaseTableName"] = DBNull.Value;
-				row ["ColumnName"] = DBNull.Value;
-				row ["IsUnique"] = false;
-				row ["NumericPrecision"] = DBNull.Value;
-				row ["NumericScale"] = DBNull.Value;
 
 				// load schema values
 				row ["ColumnOrdinal"] = schema.ColumnOrdinal;
@@ -641,6 +650,8 @@ namespace System.Data.SqlClient {
 			schemaTable.Rows.Clear ();
 
 			moreResults = command.Tds.NextResult ();
+			GetSchemaTable ();
+
 			rowsRead = 0;
 			resultsRead += 1;
 			return moreResults;

+ 0 - 51
mcs/class/System.Data/System.Data.SqlClient/SqlError.cs

@@ -52,45 +52,34 @@ namespace System.Data.SqlClient {
 		
 		#region Properties
 
-		[MonoTODO]
-		/// <summary>
-		/// severity level of the error
-		/// </summary>
 		public byte Class {
 			get { return theClass; }
 		}
 
-		[MonoTODO]
 		public int LineNumber {
 			get { return lineNumber; }
 		}
 
-		[MonoTODO]
 		public string Message {
 			get { return message; }
 		}
 		
-		[MonoTODO]
 		public int Number {
 			get { return number; }
 		}
 
-		[MonoTODO]
 		public string Procedure {
 			get { return procedure; }
 		}
 
-		[MonoTODO]
 		public string Server {
 			get { return server; }
 		}
 
-		[MonoTODO]
 		public string Source {
 			get { return source; }
 		}
 
-		[MonoTODO]
 		public byte State {
 			get { return state; }
 		}
@@ -110,46 +99,6 @@ namespace System.Data.SqlClient {
 			return toStr;
 		}
 
-		internal void SetClass (byte theClass) 
-		{
-			this.theClass = theClass;
-		}
-
-		internal void SetLineNumber (int lineNumber) 
-		{
-			this.lineNumber = lineNumber;
-		}
-
-		internal void SetMessage (string message) 
-		{
-			this.message = message;
-		}
-
-		internal void SetNumber (int number) 
-		{
-			this.number = number;
-		}
-
-		internal void SetProcedure (string procedure) 
-		{
-			this.procedure = procedure;
-		}
-
-		internal void SetServer (string server) 
-		{
-			this.server = server;
-		}
-
-		internal void SetSource (string source) 
-		{
-			this.source = source;
-		}
-
-		internal void SetState (byte state) 
-		{
-			this.state = state;
-		}
-
 		#endregion
 		
 	}

+ 86 - 0
mcs/class/System.Data/System.Data.SqlClient/SqlParameter.cs

@@ -85,6 +85,39 @@ namespace System.Data.SqlClient {
 			this.objValue = value;
 		}
 
+		internal SqlParameter (object[] dbValues)
+		{
+			precision = 0;
+			scale = 0;
+			direction = ParameterDirection.Input;
+
+			parmName = (string) dbValues[3];
+
+			switch ((short) dbValues[5]) {
+			case 1:
+				direction = ParameterDirection.Input;
+				break;
+			case 2:
+				direction = ParameterDirection.Output;
+				break;
+			case 3:
+				direction = ParameterDirection.InputOutput;
+				break;
+			case 4:
+				direction = ParameterDirection.ReturnValue;
+				break;
+			}
+
+			isNullable = (bool) dbValues[8];
+
+			if (dbValues[12] != null)
+				precision = (byte) ((short) dbValues[12]);
+			if (dbValues[13] != null)
+				scale = (byte) ((short) dbValues[13]);
+
+			dbtype = TypeNameToSqlDbType ((string) dbValues[16]);
+		}
+
 		#endregion // Constructors
 
 		#region Properties
@@ -231,6 +264,59 @@ namespace System.Data.SqlClient {
                         return result.ToString ();
 		}
 
+		internal static SqlDbType TypeNameToSqlDbType (string typeName)
+		{
+			switch (typeName) {
+			case "bigint":
+				return SqlDbType.BigInt;
+			case "binary":
+				return SqlDbType.Binary;
+			case "bit":
+				return SqlDbType.Bit;
+			case "char":
+				return SqlDbType.Char;
+			case "datetime":
+				return SqlDbType.DateTime;
+			case "decimal":
+				return SqlDbType.Decimal;
+			case "float":
+				return SqlDbType.Float;
+			case "image":
+				return SqlDbType.Image;
+			case "int":
+				return SqlDbType.Int;
+			case "money":
+				return SqlDbType.Money;
+			case "nchar":
+				return SqlDbType.NChar;
+			case "ntext":
+				return SqlDbType.NText;
+			case "nvarchar":
+				return SqlDbType.NVarChar;
+			case "real":
+				return SqlDbType.Real;
+			case "smalldatetime":
+				return SqlDbType.SmallDateTime;
+			case "smallint":
+				return SqlDbType.SmallInt;
+			case "smallmoney":
+				return SqlDbType.SmallMoney;
+			case "text":
+				return SqlDbType.Text;
+			case "timestamp":
+				return SqlDbType.Timestamp;
+			case "tinyint":
+				return SqlDbType.TinyInt;
+			case "uniqueidentifier":
+				return SqlDbType.UniqueIdentifier;
+			case "varbinary":
+				return SqlDbType.VarBinary;
+			case "varchar":
+				return SqlDbType.VarChar;
+			}
+			return SqlDbType.Variant;
+		}
+
 		public override string ToString() 
 		{
 			return parmName;

+ 18 - 1
mcs/class/System.Data/System.Data.SqlClient/SqlParameterConverter.cs

@@ -9,9 +9,10 @@
 
 using System;
 using System.ComponentModel;
+using System.Globalization;
 
 namespace System.Data.SqlClient {
-	internal sealed class SqlParameterConverter : TypeConverter
+	internal sealed class SqlParameterConverter : ExpandableObjectConverter
 	{
 		#region Constructors
 
@@ -22,5 +23,21 @@ namespace System.Data.SqlClient {
 		}
 
 		#endregion // Constructors
+
+		#region Methods
+	
+		[MonoTODO]
+		public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
+		{
+			throw new NotImplementedException ();
+		}
+
+		[MonoTODO]
+		public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
+		{
+			throw new NotImplementedException ();
+		}
+
+		#endregion // Methods
 	}
 }