Browse Source

2002-11-26 Tim Coleman <[email protected]>
* System.Data.SqlClient/SqlCommand.cs:
* System.Data.SqlClient/SqlConnection.cs:
* System.Data.SqlClient/SqlDataReader.cs:
* System.Data.SqlClient/SqlParameter.cs:
* System.Data.SqlClient/SqlParameterCollection.cs:
* System.Data.SqlClient/SqlTransaction.cs:
Many changes around restructuring of parameter
information so that the Sybase provider supports
PREPAREs too.

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

Tim Coleman 23 years ago
parent
commit
db177b4a47

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

@@ -1,3 +1,14 @@
+2002-11-26  Tim Coleman <[email protected]>
+	* System.Data.SqlClient/SqlCommand.cs:
+	* System.Data.SqlClient/SqlConnection.cs:
+	* System.Data.SqlClient/SqlDataReader.cs:
+	* System.Data.SqlClient/SqlParameter.cs:
+	* System.Data.SqlClient/SqlParameterCollection.cs:
+	* System.Data.SqlClient/SqlTransaction.cs:
+		Many changes around restructuring of parameter
+		information so that the Sybase provider supports
+		PREPAREs too.
+
 2002-11-25  Ville Palo <[email protected]>
 
 	* System.Data/DataSet.cs : Started to implement ReadXmlSchema -method

+ 63 - 193
mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs

@@ -11,6 +11,7 @@
 // Copyright (C) Tim Coleman, 2002
 //
 
+using Mono.Data.Tds;
 using Mono.Data.Tds.Protocol;
 using System;
 using System.Collections;
@@ -28,19 +29,16 @@ namespace System.Data.SqlClient {
 		#region Fields
 
 		bool disposed = false;
-
 		int commandTimeout;
 		bool designTimeVisible;
 		string commandText;
-
 		CommandType commandType;
 		SqlConnection connection;
 		SqlTransaction transaction;
 		UpdateRowSource updatedRowSource;
-
 		CommandBehavior behavior = CommandBehavior.Default;
-		NameValueCollection preparedStatements = new NameValueCollection ();
 		SqlParameterCollection parameters;
+		string preparedStatement = null;
 
 		#endregion // Fields
 
@@ -90,7 +88,11 @@ namespace System.Data.SqlClient {
 		[RefreshProperties (RefreshProperties.All)]
 		public string CommandText {
 			get { return commandText; }
-			set { commandText = value; }
+			set { 
+				if (value != commandText && preparedStatement != null)
+					Unprepare ();
+				commandText = value; 
+			}
 		}
 
 		[DataSysDescription ("Time to wait for command to execute.")]
@@ -191,137 +193,6 @@ namespace System.Data.SqlClient {
 
 		#region Methods
 
-		private string BuildCommand ()
-		{
-			string statementHandle = preparedStatements [commandText];
-			if (statementHandle != null) {
-				string proc = String.Format ("sp_execute {0}", statementHandle);	
-				if (parameters.Count > 0)
-					proc += ",";
-				return BuildProcedureCall (proc, parameters);
-			}
-
-			if (commandType == CommandType.StoredProcedure)
-				return BuildProcedureCall (commandText, parameters);
-
-			string sql = String.Empty;
-			if ((behavior & CommandBehavior.KeyInfo) > 0)
-				sql += "SET FMTONLY OFF; SET NO_BROWSETABLE ON;";
-			if ((behavior & CommandBehavior.SchemaOnly) > 0)
-				sql += "SET FMTONLY ON;";
-	
-			switch (commandType) {
-			case CommandType.Text :
-				sql += commandText;
-				break;
-			default:
-				throw new InvalidOperationException ("The CommandType was invalid.");
-			}
-			return BuildExec (sql);
-		}
-
-		private string BuildExec (string sql)
-		{
-			StringBuilder parms = new StringBuilder ();
-			foreach (SqlParameter parameter in parameters) {
-				if (parms.Length > 0)
-					parms.Append (", ");
-				parms.Append (parameter.Prepare (parameter.ParameterName));
-				if (parameter.Direction == ParameterDirection.Output)
-					parms.Append (" output");
-			}
-
-			SqlParameterCollection localParameters = new SqlParameterCollection (this);
-		
-			localParameters.Add ("@P1", SqlDbType.NVarChar, sql.Length).Value = sql;
-
-			if (parameters.Count > 0) 
-				localParameters.Add ("@P2", SqlDbType.NVarChar, parms.ToString ().Length).Value = parms.ToString ();
-
-			foreach (SqlParameter p in parameters)
-				localParameters.Add ((SqlParameter) ((ICloneable) p).Clone ());
-
-			return BuildProcedureCall ("sp_executesql", localParameters);
-		}
-
-		private string BuildPrepare ()
-		{
-			StringBuilder parms = new StringBuilder ();
-			foreach (SqlParameter parameter in parameters) {
-				if (parms.Length > 0)
-					parms.Append (", ");
-				parms.Append (parameter.Prepare (parameter.ParameterName));
-				if (parameter.Direction == ParameterDirection.Output)
-					parms.Append (" output");
-			}
-
-			SqlParameterCollection localParameters = new SqlParameterCollection (this);
-			SqlParameter parm;
-		
-			parm = new SqlParameter ("@P1", SqlDbType.Int);
-			parm.Direction = ParameterDirection.Output;
-			localParameters.Add (parm);
-
-			parm = new SqlParameter ("@P2", SqlDbType.NVarChar);
-			parm.Value = parms.ToString ();
-			parm.Size = ((string) parm.Value).Length;
-			localParameters.Add (parm);
-
-			parm = new SqlParameter ("@P3", SqlDbType.NVarChar);
-			parm.Value = commandText;
-			parm.Size = ((string) parm.Value).Length;
-			localParameters.Add (parm);
-
-			return BuildProcedureCall ("sp_prepare", localParameters);
-		}
-
-		private static string BuildProcedureCall (string procedure, SqlParameterCollection parameters)
-		{
-			StringBuilder parms = new StringBuilder ();
-			StringBuilder declarations = new StringBuilder ();
-			StringBuilder outParms = new StringBuilder ();
-			StringBuilder set = new StringBuilder ();
-
-			int index = 1;
-			foreach (SqlParameter parameter in parameters) {
-				string parmName = String.Format ("@P{0}", index);
-
-				switch (parameter.Direction) {
-				case ParameterDirection.Input :
-					if (parms.Length > 0)
-						parms.Append (", ");
-					parms.Append (FormatParameter (parameter));
-					break;
-				case ParameterDirection.Output :
-					if (parms.Length > 0)
-						parms.Append (", ");
-					parms.Append (parmName);
-					parms.Append (" output");
-
-					if (outParms.Length > 0) {
-						outParms.Append (", ");
-						declarations.Append (", ");
-					}
-					else {
-						outParms.Append ("select ");
-						declarations.Append ("declare ");
-					}
-
-					declarations.Append (parameter.Prepare (parmName));
-					set.Append (String.Format ("set {0}=NULL\n", parmName));
-					outParms.Append (parmName);
-					break;
-				default :
-					throw new NotImplementedException ("Only support input and output parameters.");
-				}
-				index += 1;
-			}
-			if (declarations.Length > 0)
-				declarations.Append ('\n');
-
-			return String.Format ("{0}{1}{2} {3}\n{4}", declarations.ToString (), set.ToString (), procedure, parms.ToString (), outParms.ToString ());
-		}
-
 		public void Cancel () 
 		{
 			if (Connection == null || Connection.Tds == null)
@@ -352,7 +223,10 @@ namespace System.Data.SqlClient {
 			SqlParameterCollection localParameters = new SqlParameterCollection (this);
 			localParameters.Add ("@P1", SqlDbType.NVarChar, commandText.Length).Value = commandText;
 
-			Connection.Tds.ExecuteQuery (BuildProcedureCall ("sp_procedure_params_rowset", localParameters));
+			string sql = "sp_procedure_params_rowset";
+
+			Connection.Tds.ExecProc (sql, localParameters.MetaParameters, 0, true);
+
 			SqlDataReader reader = new SqlDataReader (this);
 			parameters.Clear ();
 			object[] dbValues = new object[reader.FieldCount];
@@ -364,19 +238,52 @@ namespace System.Data.SqlClient {
 			reader.Close ();	
 		}
 
+		private void Execute (CommandBehavior behavior, bool wantResults)
+		{
+			TdsMetaParameterCollection parms = Parameters.MetaParameters;
+			if (preparedStatement == null) {
+				bool schemaOnly = ((CommandBehavior & CommandBehavior.SchemaOnly) > 0);
+				bool keyInfo = ((CommandBehavior & CommandBehavior.SchemaOnly) > 0);
+
+				StringBuilder sql1 = new StringBuilder ();
+				StringBuilder sql2 = new StringBuilder ();
+
+				if (schemaOnly || keyInfo)
+					sql1.Append ("SET FMTONLY OFF;");
+				if (keyInfo) {
+					sql1.Append ("SET NO_BROWSETABLE ON;");
+					sql2.Append ("SET NO_BROWSETABLE OFF;");
+				}
+				if (schemaOnly) {
+					sql1.Append ("SET FMTONLY ON;");
+					sql2.Append ("SET FMTONLY OFF;");
+				}
+
+				switch (CommandType) {
+				case CommandType.StoredProcedure:
+					if (keyInfo || schemaOnly)
+						Connection.Tds.Execute (sql1.ToString ());
+					Connection.Tds.ExecProc (CommandText, parms, CommandTimeout, wantResults);
+					if (keyInfo || schemaOnly)
+						Connection.Tds.Execute (sql2.ToString ());
+					break;
+				case CommandType.Text:
+					string sql = String.Format ("{0}{1}{2}", sql1.ToString (), CommandText, sql2.ToString ());
+					Connection.Tds.Execute (sql, parms, CommandTimeout, wantResults);
+					break;
+				}
+			}
+			else 
+				Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults);
+		}
+
 		public int ExecuteNonQuery ()
 		{
 			ValidateCommand ("ExecuteNonQuery");
-			string sql = String.Empty;
 			int result = 0;
 
-			if (Parameters.Count > 0)
-				sql = BuildCommand ();
-			else
-				sql = CommandText;
-
 			try {
-				result = Connection.Tds.ExecuteNonQuery (sql, CommandTimeout);
+				Execute (CommandBehavior.Default, false);
 			}
 			catch (TdsTimeoutException e) {
 				throw SqlException.FromTdsInternalException ((TdsInternalException) e);
@@ -394,15 +301,12 @@ namespace System.Data.SqlClient {
 		public SqlDataReader ExecuteReader (CommandBehavior behavior)
 		{
 			ValidateCommand ("ExecuteReader");
-			this.behavior = behavior;
-
 			try {
-				Connection.Tds.ExecuteQuery (BuildCommand (), CommandTimeout);
+				Execute (behavior, true);
 			}
 			catch (TdsTimeoutException e) {
 				throw SqlException.FromTdsInternalException ((TdsInternalException) e);
 			}
-		
 			Connection.DataReader = new SqlDataReader (this);
 			return Connection.DataReader;
 		}
@@ -411,7 +315,7 @@ namespace System.Data.SqlClient {
 		{
 			ValidateCommand ("ExecuteScalar");
 			try {
-				Connection.Tds.ExecuteQuery (BuildCommand (), CommandTimeout);
+				Execute (CommandBehavior.Default, true);
 			}
 			catch (TdsTimeoutException e) {
 				throw SqlException.FromTdsInternalException ((TdsInternalException) e);
@@ -428,9 +332,8 @@ namespace System.Data.SqlClient {
 		public XmlReader ExecuteXmlReader ()
 		{
 			ValidateCommand ("ExecuteXmlReader");
-
-			try {
-				Connection.Tds.ExecuteQuery (BuildCommand (), CommandTimeout);
+			try { 
+				Execute (CommandBehavior.Default, true);
 			}
 			catch (TdsTimeoutException e) {
 				throw SqlException.FromTdsInternalException ((TdsInternalException) e);
@@ -442,41 +345,6 @@ namespace System.Data.SqlClient {
 			return xmlReader;
 		}
 
-		[MonoTODO ("Include offset from SqlParameter for binary/string types.")]
-		static string FormatParameter (SqlParameter parameter)
-		{
-			if (parameter.Value == null)
-				return "NULL";
-
-			switch (parameter.SqlDbType) {
-				case SqlDbType.BigInt :
-				case SqlDbType.Decimal :
-				case SqlDbType.Float :
-				case SqlDbType.Int :
-				case SqlDbType.Money :
-				case SqlDbType.Real :
-				case SqlDbType.SmallInt :
-				case SqlDbType.SmallMoney :
-				case SqlDbType.TinyInt :
-					return parameter.Value.ToString ();
-				case SqlDbType.NVarChar :
-				case SqlDbType.NChar :
-					return String.Format ("N'{0}'", parameter.Value.ToString ().Replace ("'", "''"));
-				case SqlDbType.UniqueIdentifier :
-					return String.Format ("0x{0}", ((Guid) parameter.Value).ToString ("N"));
-				case SqlDbType.Bit:
-					if (parameter.Value.GetType () == typeof (bool))
-						return (((bool) parameter.Value) ? "0x1" : "0x0");
-					return parameter.Value.ToString ();
-				case SqlDbType.Image:
-				case SqlDbType.Binary:
-				case SqlDbType.VarBinary:
-					return String.Format ("0x{0}", BitConverter.ToString ((byte[]) parameter.Value).Replace ("-", "").ToLower ());
-				default:
-					return String.Format ("'{0}'", parameter.Value.ToString ().Replace ("'", "''"));
-			}
-		}
-
 		private void GetOutputParameters ()
 		{
 			Connection.Tds.SkipToEnd ();
@@ -519,12 +387,8 @@ namespace System.Data.SqlClient {
 		public void Prepare ()
 		{
 			ValidateCommand ("Prepare");
-			Connection.Tds.ExecuteNonQuery (BuildPrepare ());
-
-			if (Connection.Tds.OutputParameters.Count == 0 || Connection.Tds.OutputParameters[0] == null)
-				throw new Exception ("Could not prepare the statement.");
-
-			preparedStatements [commandText] = ((int) Connection.Tds.OutputParameters [0]).ToString ();
+			if (CommandType == CommandType.Text) 
+				preparedStatement = Connection.Tds.Prepare (CommandText, Parameters.MetaParameters);
 		}
 
 		public void ResetCommandTimeout ()
@@ -532,6 +396,12 @@ namespace System.Data.SqlClient {
 			commandTimeout = 30;
 		}
 
+		private void Unprepare ()
+		{
+			Connection.Tds.Unprepare (preparedStatement);
+			preparedStatement = null;
+		}
+
 		private void ValidateCommand (string method)
 		{
 			if (Connection == null)

+ 4 - 3
mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs

@@ -11,6 +11,7 @@
 // Copyright (C) Tim Coleman, 2002
 //
 
+using Mono.Data.Tds;
 using Mono.Data.Tds.Protocol;
 using System;
 using System.Collections;
@@ -224,7 +225,7 @@ namespace System.Data.SqlClient {
 				break;
 			}
 
-			tds.ExecuteNonQuery (String.Format ("SET TRANSACTION ISOLATION LEVEL {0};BEGIN TRANSACTION {1}", isolevel, transactionName));
+			tds.Execute (String.Format ("SET TRANSACTION ISOLATION LEVEL {0};BEGIN TRANSACTION {1}", isolevel, transactionName));
 
 			transaction = new SqlTransaction (this, iso);
 			return transaction;
@@ -236,7 +237,7 @@ namespace System.Data.SqlClient {
 				throw new ArgumentException (String.Format ("The database name {0} is not valid."));
 			if (state != ConnectionState.Open)
 				throw new InvalidOperationException ("The connection is not open.");
-			tds.ExecuteNonQuery (String.Format ("use {0}", database));
+			tds.Execute (String.Format ("use {0}", database));
 		}
 
 		private void ChangeState (ConnectionState currentState)
@@ -351,7 +352,7 @@ namespace System.Data.SqlClient {
 			if (!tds.IsConnected) 
 				tds.Connect (parms);
 			else if (connectionReset)
-				tds.ExecuteNonQuery ("EXEC sp_reset_connection");
+				tds.ExecProc ("sp_reset_connection");
 				
 			ChangeState (ConnectionState.Open);
 		}

+ 49 - 31
mcs/class/System.Data/System.Data.SqlClient/SqlDataReader.cs

@@ -320,6 +320,55 @@ namespace System.Data.SqlClient {
 					row ["BaseColumnName"] = row ["ColumnName"];
 
 				switch ((TdsColumnType) schema ["ColumnType"]) {
+					case TdsColumnType.Int1:
+					case TdsColumnType.Int2:
+					case TdsColumnType.Int4:
+					case TdsColumnType.IntN:
+						switch ((int) schema ["ColumnSize"]) {
+						case 1:
+							dataTypeNames.Add ("tinyint");
+							row ["ProviderType"] = (int) SqlDbType.TinyInt;
+							row ["DataType"] = typeof (byte);
+							row ["IsLong"] = false;
+							break;
+						case 2:
+							dataTypeNames.Add ("smallint");
+							row ["ProviderType"] = (int) SqlDbType.SmallInt;
+							row ["DataType"] = typeof (short);
+							row ["IsLong"] = false;
+							break;
+						case 4:
+							dataTypeNames.Add ("int");
+							row ["ProviderType"] = (int) SqlDbType.Int;
+							row ["DataType"] = typeof (int);
+							row ["IsLong"] = false;
+							break;
+						case 8:
+							dataTypeNames.Add ("bigint");
+							row ["ProviderType"] = (int) SqlDbType.BigInt;
+							row ["DataType"] = typeof (long);
+							row ["IsLong"] = false;
+							break;
+						}
+						break;
+					case TdsColumnType.Real:
+					case TdsColumnType.Float8:
+					case TdsColumnType.FloatN:
+						switch ((int) schema ["ColumnSize"]) {
+						case 4:
+							dataTypeNames.Add ("real");
+							row ["ProviderType"] = (int) SqlDbType.Real;
+							row ["DataType"] = typeof (float);
+							row ["IsLong"] = false;
+							break;
+						case 8:
+							dataTypeNames.Add ("float");
+							row ["ProviderType"] = (int) SqlDbType.Float;
+							row ["DataType"] = typeof (double);
+							row ["IsLong"] = false;
+							break;
+						}
+						break;
 					case TdsColumnType.Image :
 						dataTypeNames.Add ("image");
 						row ["ProviderType"] = (int) SqlDbType.Image;
@@ -345,13 +394,6 @@ namespace System.Data.SqlClient {
 						row ["DataType"] = typeof (byte[]);
 						row ["IsLong"] = true;
 						break;
-					case TdsColumnType.IntN :
-					case TdsColumnType.Int4 :
-						dataTypeNames.Add ("int");
-						row ["ProviderType"] = (int) SqlDbType.Int;
-						row ["DataType"] = typeof (int);
-						row ["IsLong"] = false;
-						break;
 					case TdsColumnType.VarChar :
 					case TdsColumnType.BigVarChar :
 						dataTypeNames.Add ("varchar");
@@ -373,12 +415,6 @@ namespace System.Data.SqlClient {
 						row ["DataType"] = typeof (string);
 						row ["IsLong"] = false;
 						break;
-					case TdsColumnType.Int1 :
-						dataTypeNames.Add ("tinyint");
-						row ["ProviderType"] = (int) SqlDbType.TinyInt;
-						row ["DataType"] = typeof (byte);
-						row ["IsLong"] = false;
-						break;
 					case TdsColumnType.Bit :
 					case TdsColumnType.BitN :
 						dataTypeNames.Add ("bit");
@@ -386,12 +422,6 @@ namespace System.Data.SqlClient {
 						row ["DataType"] = typeof (bool);
 						row ["IsLong"] = false;
 						break;
-					case TdsColumnType.Int2 :
-						dataTypeNames.Add ("smallint");
-						row ["ProviderType"] = (int) SqlDbType.SmallInt;
-						row ["DataType"] = typeof (short);
-						row ["IsLong"] = false;
-						break;
 					case TdsColumnType.DateTime4 :
 					case TdsColumnType.DateTime :
 					case TdsColumnType.DateTimeN :
@@ -400,11 +430,6 @@ namespace System.Data.SqlClient {
 						row ["DataType"] = typeof (DateTime);
 						row ["IsLong"] = false;
 						break;
-					case TdsColumnType.Real :
-						dataTypeNames.Add ("real");
-						row ["ProviderType"] = (int) SqlDbType.Real;
-						row ["DataType"] = typeof (float);
-						break;
 					case TdsColumnType.Money :
 					case TdsColumnType.MoneyN :
 					case TdsColumnType.Money4 :
@@ -413,13 +438,6 @@ namespace System.Data.SqlClient {
 						row ["DataType"] = typeof (decimal);
 						row ["IsLong"] = false;
 						break;
-					case TdsColumnType.Float8 :
-					case TdsColumnType.FloatN :
-						dataTypeNames.Add ("float");
-						row ["ProviderType"] = (int) SqlDbType.Float;
-						row ["DataType"] = typeof (double);
-						row ["IsLong"] = false;
-						break;
 					case TdsColumnType.NText :
 						dataTypeNames.Add ("ntext");
 						row ["ProviderType"] = (int) SqlDbType.NText;

+ 83 - 118
mcs/class/System.Data/System.Data.SqlClient/SqlParameter.cs

@@ -10,6 +10,7 @@
 // Copyright (C) Tim Coleman, 2002
 //
 
+using Mono.Data.Tds;
 using Mono.Data.Tds.Protocol;
 using System;
 using System.ComponentModel;
@@ -23,22 +24,18 @@ namespace System.Data.SqlClient {
 	{
 		#region Fields
 
+		TdsMetaParameter metaParameter;
+
 		SqlParameterCollection container = null;
 		DbType dbType;
 		ParameterDirection direction = ParameterDirection.Input;
 		bool isNullable;
 		bool isSizeSet = false;
 		bool isTypeSet = false;
-		object objValue;
 		int offset;
-		string parameterName;
-		byte precision;
-		byte scale;
-		int size;
 		SqlDbType sqlDbType;
 		string sourceColumn;
 		DataRowVersion sourceVersion;
-		string typeName;
 
 		#endregion // Fields
 
@@ -51,8 +48,7 @@ namespace System.Data.SqlClient {
 
 		public SqlParameter (string parameterName, object value) 
 		{
-			this.parameterName = parameterName;
-			this.objValue = value;
+			metaParameter = new TdsMetaParameter (parameterName, value);
 			this.sourceVersion = DataRowVersion.Current;
 			InferSqlType (value);
 		}
@@ -75,15 +71,10 @@ namespace System.Data.SqlClient {
 		[EditorBrowsable (EditorBrowsableState.Advanced)]	 
 		public SqlParameter (string parameterName, SqlDbType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value) 
 		{
-			SqlDbType = dbType;
-			Size = size;
-			Value = value;
+			metaParameter = new TdsMetaParameter (parameterName, size, isNullable, precision, scale, value);
 
-			ParameterName = parameterName;
+			SqlDbType = dbType;
 			Direction = direction;
-			IsNullable = isNullable;
-			Precision = precision;
-			Scale = scale;
 			SourceColumn = sourceColumn;
 			SourceVersion = sourceVersion;
 		}
@@ -93,33 +84,33 @@ namespace System.Data.SqlClient {
 		// This is in SqlCommand.DeriveParameters.
 		internal SqlParameter (object[] dbValues)
 		{
-			precision = 0;
-			scale = 0;
-			direction = ParameterDirection.Input;
+			Precision = 0;
+			Scale = 0;
+			Direction = ParameterDirection.Input;
 
-			parameterName = (string) dbValues[3];
+			ParameterName = (string) dbValues[3];
 
 			switch ((short) dbValues[5]) {
 			case 1:
-				direction = ParameterDirection.Input;
+				Direction = ParameterDirection.Input;
 				break;
 			case 2:
-				direction = ParameterDirection.Output;
+				Direction = ParameterDirection.Output;
 				break;
 			case 3:
-				direction = ParameterDirection.InputOutput;
+				Direction = ParameterDirection.InputOutput;
 				break;
 			case 4:
-				direction = ParameterDirection.ReturnValue;
+				Direction = ParameterDirection.ReturnValue;
 				break;
 			}
 
-			isNullable = (bool) dbValues[8];
+			IsNullable = (bool) dbValues[8];
 
 			if (dbValues[12] != null)
-				precision = (byte) ((short) dbValues[12]);
+				Precision = (byte) ((short) dbValues[12]);
 			if (dbValues[13] != null)
-				scale = (byte) ((short) dbValues[13]);
+				Scale = (byte) ((short) dbValues[13]);
 
 			SetDbTypeName ((string) dbValues[16]);
 		}
@@ -153,12 +144,20 @@ namespace System.Data.SqlClient {
 		[DefaultValue (ParameterDirection.Input)]
 		public ParameterDirection Direction {
 			get { return direction; }
-			set { direction = value; }
+			set { 
+				direction = value; 
+				if (direction == ParameterDirection.Output)
+					MetaParameter.Direction = TdsParameterDirection.Output;
+			}
+		}
+
+		internal TdsMetaParameter MetaParameter {
+			get { return metaParameter; }
 		}
 
 		string IDataParameter.ParameterName {
-			get { return parameterName; }
-			set { parameterName = value; }
+			get { return metaParameter.ParameterName; }
+			set { metaParameter.ParameterName = value; }
 		}
 
 		[Browsable (false)]
@@ -167,8 +166,8 @@ namespace System.Data.SqlClient {
 		[DesignOnly (true)]
 		[EditorBrowsable (EditorBrowsableState.Advanced)]	 
 		public bool IsNullable	{
-			get { return isNullable; }
-			set { isNullable = value; }
+			get { return metaParameter.IsNullable; }
+			set { metaParameter.IsNullable = value; }
 		}
 
 		[Browsable (false)]
@@ -183,35 +182,32 @@ namespace System.Data.SqlClient {
 		[DataSysDescription ("Name of the parameter, like '@p1'")]
 		[DefaultValue ("")]
 		public string ParameterName {
-			get { return parameterName; }
-			set { parameterName = value; }
+			get { return metaParameter.ParameterName; }
+			set { metaParameter.ParameterName = value; }
 		}
 
 		[DataCategory ("Data")]
 		[DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
 		[DefaultValue (0)]
 		public byte Precision {
-			get { return precision; }
-			set { precision = value; }
+			get { return metaParameter.Precision; }
+			set { metaParameter.Precision = value; }
 		}
 
 		[DataCategory ("Data")]
 		[DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
 		[DefaultValue (0)]
                 public byte Scale {
-			get { return scale; }
-			set { scale = value; }
+			get { return metaParameter.Scale; }
+			set { metaParameter.Scale = value; }
 		}
 
 		[DataCategory ("Data")]
 		[DataSysDescription ("Size of variable length datatypes (strings & arrays).")]
 		[DefaultValue (0)]
                 public int Size {
-			get { return size; }
-			set { 
-				size = value; 
-				isSizeSet = true;
-			}
+			get { return metaParameter.Size; }
+			set { metaParameter.Size = value; }
 		}
 
 		[DataCategory ("Data")]
@@ -246,11 +242,11 @@ namespace System.Data.SqlClient {
 		[DataSysDescription ("Value of the parameter.")]
 		[DefaultValue (null)]
 		public object Value {
-			get { return objValue; }
+			get { return metaParameter.Value; }
 			set { 
 				if (!isTypeSet)
 					InferSqlType (value);
-				objValue = value; 
+				metaParameter.Value = value; 
 			}
 		}
 
@@ -316,37 +312,6 @@ namespace System.Data.SqlClient {
 			}
 		}
 
-		internal string Prepare (string name)
-		{
-			StringBuilder result = new StringBuilder ();
-			result.Append (name);
-			result.Append (" ");
-			result.Append (typeName);
-
-			switch (sqlDbType) {
-			case SqlDbType.VarBinary :
-			case SqlDbType.NVarChar :
-			case SqlDbType.VarChar :
-				if (!isSizeSet || size == 0)
-					throw new InvalidOperationException ("All variable length parameters must have an explicitly set non-zero size.");
-				result.Append (String.Format ("({0})", size));
-				break;
-			case SqlDbType.NChar :
-			case SqlDbType.Char :
-			case SqlDbType.Binary :
-				if (size > 0) 
-					result.Append (String.Format ("({0})", size));
-				break;
-			case SqlDbType.Decimal :
-				result.Append (String.Format ("({0},{1})", precision, scale));
-				break;
-                        default:
-                                break;
-                        }
-
-                        return result.ToString ();
-		}
-
 		// When the DbType is set, we also set the SqlDbType, as well as the SQL Server
 		// string representation of the type name.  If the DbType is not convertible
 		// to an SqlDbType, throw an exception.
@@ -356,76 +321,76 @@ namespace System.Data.SqlClient {
 
 			switch (type) {
 			case DbType.AnsiString:
-				typeName = "varchar";
+				MetaParameter.TypeName = "varchar";
 				sqlDbType = SqlDbType.VarChar;
 				break;
 			case DbType.AnsiStringFixedLength:
-				typeName = "char";
+				MetaParameter.TypeName = "char";
 				sqlDbType = SqlDbType.Char;
 				break;
 			case DbType.Binary:
-				typeName = "varbinary";
+				MetaParameter.TypeName = "varbinary";
 				sqlDbType = SqlDbType.VarBinary;
 				break;
 			case DbType.Boolean:
-				typeName = "bit";
+				MetaParameter.TypeName = "bit";
 				sqlDbType = SqlDbType.Bit;
 				break;
 			case DbType.Byte:
-				typeName = "tinyint";
+				MetaParameter.TypeName = "tinyint";
 				sqlDbType = SqlDbType.TinyInt;
 				break;
 			case DbType.Currency:
 				sqlDbType = SqlDbType.Money;
-				typeName = "money";
+				MetaParameter.TypeName = "money";
 				break;
 			case DbType.Date:
 			case DbType.DateTime:
-				typeName = "datetime";
+				MetaParameter.TypeName = "datetime";
 				sqlDbType = SqlDbType.DateTime;
 				break;
 			case DbType.Decimal:
-				typeName = "decimal";
+				MetaParameter.TypeName = "decimal";
 				sqlDbType = SqlDbType.Decimal;
 				break;
 			case DbType.Double:
-				typeName = "float";
+				MetaParameter.TypeName = "float";
 				sqlDbType = SqlDbType.Float;
 				break;
 			case DbType.Guid:
-				typeName = "uniqueidentifier";
+				MetaParameter.TypeName = "uniqueidentifier";
 				sqlDbType = SqlDbType.UniqueIdentifier;
 				break;
 			case DbType.Int16:
-				typeName = "smallint";
+				MetaParameter.TypeName = "smallint";
 				sqlDbType = SqlDbType.SmallInt;
 				break;
 			case DbType.Int32:
-				typeName = "int";
+				MetaParameter.TypeName = "int";
 				sqlDbType = SqlDbType.Int;
 				break;
 			case DbType.Int64:
-				typeName = "bigint";
+				MetaParameter.TypeName = "bigint";
 				sqlDbType = SqlDbType.BigInt;
 				break;
 			case DbType.Object:
-				typeName = "sql_variant";
+				MetaParameter.TypeName = "sql_variant";
 				sqlDbType = SqlDbType.Variant;
 				break;
 			case DbType.Single:
-				typeName = "real";
+				MetaParameter.TypeName = "real";
 				sqlDbType = SqlDbType.Real;
 				break;
 			case DbType.String:
-				typeName = "nvarchar";
+				MetaParameter.TypeName = "nvarchar";
 				sqlDbType = SqlDbType.NVarChar;
 				break;
 			case DbType.StringFixedLength:
-				typeName = "nchar";
+				MetaParameter.TypeName = "nchar";
 				sqlDbType = SqlDbType.NChar;
 				break;
 			case DbType.Time:
-				typeName = "datetime";
+				MetaParameter.TypeName = "datetime";
 				sqlDbType = SqlDbType.DateTime;
 				break;
 			default:
@@ -522,99 +487,99 @@ namespace System.Data.SqlClient {
 
 			switch (type) {
 			case SqlDbType.BigInt:
-				typeName = "bigint";
+				MetaParameter.TypeName = "bigint";
 				dbType = DbType.Int64;
 				break;
 			case SqlDbType.Binary:
-				typeName = "binary";
+				MetaParameter.TypeName = "binary";
 				dbType = DbType.Binary;
 				break;
 			case SqlDbType.Timestamp:
-				typeName = "timestamp";
+				MetaParameter.TypeName = "timestamp";
 				dbType = DbType.Binary;
 				break;
 			case SqlDbType.VarBinary:
-				typeName = "varbinary";
+				MetaParameter.TypeName = "varbinary";
 				dbType = DbType.Binary;
 				break;
 			case SqlDbType.Bit:
-				typeName = "bit";
+				MetaParameter.TypeName = "bit";
 				dbType = DbType.Boolean;
 				break;
 			case SqlDbType.Char:
-				typeName = "char";
+				MetaParameter.TypeName = "char";
 				dbType = DbType.AnsiStringFixedLength;
 				break;
 			case SqlDbType.DateTime:
-				typeName = "datetime";
+				MetaParameter.TypeName = "datetime";
 				dbType = DbType.DateTime;
 				break;
 			case SqlDbType.SmallDateTime:
-				typeName = "smalldatetime";
+				MetaParameter.TypeName = "smalldatetime";
 				dbType = DbType.DateTime;
 				break;
 			case SqlDbType.Decimal:
-				typeName = "decimal";
+				MetaParameter.TypeName = "decimal";
 				dbType = DbType.Decimal;
 				break;
 			case SqlDbType.Float:
-				typeName = "float";
+				MetaParameter.TypeName = "float";
 				dbType = DbType.Double;
 				break;
 			case SqlDbType.Image:
-				typeName = "image";
+				MetaParameter.TypeName = "image";
 				dbType = DbType.Binary;
 				break;
 			case SqlDbType.Int:
-				typeName = "int";
+				MetaParameter.TypeName = "int";
 				dbType = DbType.Int32;
 				break;
 			case SqlDbType.Money:
-				typeName = "money";
+				MetaParameter.TypeName = "money";
 				dbType = DbType.Currency;
 				break;
 			case SqlDbType.SmallMoney:
-				typeName = "smallmoney";
+				MetaParameter.TypeName = "smallmoney";
 				dbType = DbType.Currency;
 				break;
 			case SqlDbType.NChar:
-				typeName = "nchar";
+				MetaParameter.TypeName = "nchar";
 				dbType = DbType.StringFixedLength;
 				break;
 			case SqlDbType.NText:
-				typeName = "ntext";
+				MetaParameter.TypeName = "ntext";
 				dbType = DbType.String;
 				break;
 			case SqlDbType.NVarChar:
-				typeName = "nvarchar";
+				MetaParameter.TypeName = "nvarchar";
 				dbType = DbType.String;
 				break;
 			case SqlDbType.Real:
-				typeName = "real";
+				MetaParameter.TypeName = "real";
 				dbType = DbType.Single;
 				break;
 			case SqlDbType.SmallInt:
-				typeName = "smallint";
+				MetaParameter.TypeName = "smallint";
 				dbType = DbType.Int16;
 				break;
 			case SqlDbType.Text:
-				typeName = "text";
+				MetaParameter.TypeName = "text";
 				dbType = DbType.AnsiString;
 				break;
 			case SqlDbType.VarChar:
-				typeName = "varchar";
+				MetaParameter.TypeName = "varchar";
 				dbType = DbType.AnsiString;
 				break;
 			case SqlDbType.TinyInt:
-				typeName = "tinyint";
+				MetaParameter.TypeName = "tinyint";
 				dbType = DbType.Byte;
 				break;
 			case SqlDbType.UniqueIdentifier:
-				typeName = "uniqueidentifier";
+				MetaParameter.TypeName = "uniqueidentifier";
 				dbType = DbType.Guid;
 				break;
 			case SqlDbType.Variant:
-				typeName = "sql_variant";
+				MetaParameter.TypeName = "sql_variant";
 				dbType = DbType.Object;
 				break;
 			default:
@@ -625,7 +590,7 @@ namespace System.Data.SqlClient {
 
 		public override string ToString() 
 		{
-			return parameterName;
+			return ParameterName;
 		}
 
 		#endregion // Methods

+ 11 - 0
mcs/class/System.Data/System.Data.SqlClient/SqlParameterCollection.cs

@@ -10,6 +10,7 @@
 // Copyright (C) Tim Coleman, 2002
 //
 
+using Mono.Data.Tds;
 using System;
 using System.ComponentModel;
 using System.Data;
@@ -23,6 +24,7 @@ namespace System.Data.SqlClient {
 		#region Fields
 
 		ArrayList list = new ArrayList();
+		TdsMetaParameterCollection metaParameters;
 		SqlCommand command;
 
 		#endregion // Fields
@@ -32,6 +34,7 @@ namespace System.Data.SqlClient {
 		internal SqlParameterCollection (SqlCommand command)
 		{
 			this.command = command;
+			metaParameters = new TdsMetaParameterCollection ();
 		}
 
 		#endregion // Constructors
@@ -96,6 +99,10 @@ namespace System.Data.SqlClient {
 		object ICollection.SyncRoot {
 			get { return list.SyncRoot; }
 		}
+
+		internal TdsMetaParameterCollection MetaParameters {
+			get { return metaParameters; }
+		}
 		
 		#endregion // Properties
 
@@ -116,6 +123,7 @@ namespace System.Data.SqlClient {
 			
 			value.Container = this;
 			list.Add (value);
+			metaParameters.Add (value.MetaParameter);
 			return value;
 		}
 		
@@ -141,6 +149,7 @@ namespace System.Data.SqlClient {
 
 		public void Clear()
 		{
+			metaParameters.Clear ();
 			list.Clear ();
 		}
 		
@@ -188,11 +197,13 @@ namespace System.Data.SqlClient {
 
 		public void Remove (object value)
 		{
+			metaParameters.Remove (((SqlParameter) value).MetaParameter);
 			list.Remove (value);
 		}
 
 		public void RemoveAt (int index)
 		{
+			metaParameters.RemoveAt (index);
 			list.RemoveAt (index);
 		}
 

+ 3 - 3
mcs/class/System.Data/System.Data.SqlClient/SqlTransaction.cs

@@ -60,7 +60,7 @@ namespace System.Data.SqlClient {
 		{
 			if (!isOpen)
 				throw new InvalidOperationException ("The Transaction was not open.");
-			connection.Tds.ExecuteNonQuery ("COMMIT TRANSACTION");
+			connection.Tds.Execute ("COMMIT TRANSACTION");
 			connection.Transaction = null;
 			isOpen = false;
 		}		
@@ -90,7 +90,7 @@ namespace System.Data.SqlClient {
 		{
 			if (!isOpen)
 				throw new InvalidOperationException ("The Transaction was not open.");
-			connection.Tds.ExecuteNonQuery (String.Format ("ROLLBACK TRANSACTION {0}", transactionName));
+			connection.Tds.Execute (String.Format ("ROLLBACK TRANSACTION {0}", transactionName));
 			isOpen = false;
 		}
 
@@ -98,7 +98,7 @@ namespace System.Data.SqlClient {
 		{
 			if (!isOpen)
 				throw new InvalidOperationException ("The Transaction was not open.");
-			connection.Tds.ExecuteNonQuery (String.Format ("SAVE TRANSACTION {0}", savePointName));
+			connection.Tds.Execute (String.Format ("SAVE TRANSACTION {0}", savePointName));
 		}
 
 		#endregion // Methods