Merge pull request #1163 from AerisG222/more_mvc_fixes
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds.Protocol / Tds50.cs
index 49ce8bd1d36b09877be6c3f3d1eab08fde1b2a2c..88219125df5f3d081963aed376c790a6cacc208f 100644 (file)
@@ -1,5 +1,5 @@
 //
-// Mono.Data.TdsClient.Internal.Tds50.cs
+// Mono.Data.Tds.Protocol.Tds50.cs
 //
 // Author:
 //   Tim Coleman (tim@timcoleman.com)
@@ -7,14 +7,42 @@
 // Copyright (C) 2002 Tim Coleman
 //
 
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using Mono.Data.Tds;
 using System;
+using System.Text;
+using System.Security;
 
-namespace Mono.Data.TdsClient.Internal {
-        internal class Tds50 : Tds
+namespace Mono.Data.Tds.Protocol
+{
+       [MonoTODO ("FIXME: Can packetsize be anything other than 512?")]
+       public sealed class Tds50 : Tds
        {
                #region Fields
 
                public static readonly TdsVersion Version = TdsVersion.tds50;
+               int packetSize;
+               bool isSelectQuery;
 
                #endregion // Fields
 
@@ -28,17 +56,49 @@ namespace Mono.Data.TdsClient.Internal {
                public Tds50 (string server, int port, int packetSize, int timeout)
                        : base (server, port, packetSize, timeout, Version)
                {
+                       this.packetSize = packetSize;
                }
 
                #endregion // Constructors
        
                #region Methods
 
+               public string BuildExec (string sql)
+               {
+                       if (Parameters == null || Parameters.Count == 0) 
+                               return sql;
+
+                       StringBuilder select = new StringBuilder ();
+                       StringBuilder set = new StringBuilder ();
+                       StringBuilder declare = new StringBuilder ();
+                       int count = 0;
+                       foreach (TdsMetaParameter p in Parameters) {
+                               declare.Append (String.Format ("declare {0}\n", p.Prepare ()));
+                               set.Append (String.Format ("select {0}=", p.ParameterName));
+                               if (p.Direction == TdsParameterDirection.Input)
+                                       set.Append (FormatParameter (p));
+                               else {
+                                       set.Append ("NULL");
+                                       select.Append (p.ParameterName);
+                                       if (count == 0)
+                                               select.Append ("select ");
+                                       else
+                                               select.Append (", ");
+                                       count += 1;
+                               }
+                               set.Append ("\n");
+                       }       
+                       return String.Format ("{0}{1}{2}\n{3}", declare.ToString (), set.ToString (), sql, select.ToString ());
+               }
+
                public override bool Connect (TdsConnectionParameters connectionParameters)
                {
                        if (IsConnected)
                                throw new InvalidOperationException ("The connection is already open.");
 
+                       byte[] capabilityRequest = {0x03, 0xef, 0x65, 0x41, 0xff, 0xff, 0xff, 0xd6};
+                       byte[] capabilityResponse = {0x00, 0x00, 0x00, 0x06, 0x48, 0x00, 0x00, 0x08};
+
                        SetCharset (connectionParameters.Charset);
                        SetLanguage (connectionParameters.Language);
 
@@ -48,44 +108,38 @@ namespace Mono.Data.TdsClient.Internal {
                        Comm.StartPacket (TdsPacketType.Logon);
 
                        // hostname (offset 0)
+                       // 0-30
                        byte[] tmp = Comm.Append (connectionParameters.Hostname, 30, pad);
                        Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
                        // username (offset 31 0x1f)
+                       // 31-61
                        tmp = Comm.Append (connectionParameters.User, 30, pad);
                        Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
                        // password (offset 62 0x3e)
-                       tmp = Comm.Append (connectionParameters.Password, 30, pad);
+                       // 62-92
+                       tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 30, pad);
                        Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
                        // hostproc (offset 93 0x5d)
-                       Comm.Append ("00000116", 8, pad);
-
-                       // unused (offset 109 0x6d)
-                       Comm.Append (empty, (30-14), pad);
-
-                       // apptype 
-                       Comm.Append ((byte) 0x0);
-                       Comm.Append ((byte) 0xa0);
-                       Comm.Append ((byte) 0x24);
-                       Comm.Append ((byte) 0xcc);
-                       Comm.Append ((byte) 0x50);
-                       Comm.Append ((byte) 0x12);
-
-                       // hostproc length 
-                       Comm.Append ((byte) 8);
+                       // 93-123
+                       tmp = Comm.Append ("37876", 30, pad);
+                       Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
                        // Byte order of 2 byte ints
                        // 2 = <MSB, LSB>, 3 = <LSB, MSB>
+                       // 124
                        Comm.Append ((byte) 3);
 
                        // Byte order of 4 byte ints
                        // 0 = <MSB, LSB>, 1 = <LSB, MSB>
+                       // 125
                        Comm.Append ((byte) 1);
 
                        // Character representation
                        // (6 = ASCII, 7 = EBCDIC)
+                       // 126
                        Comm.Append ((byte) 6);
 
                        // Eight byte floating point representation
@@ -93,184 +147,488 @@ namespace Mono.Data.TdsClient.Internal {
                        // 5 = VAX 'D'
                        // 10 = IEEE <LSB, ..., MSB>
                        // 11 = ND5000
+                       // 127
                        Comm.Append ((byte) 10);
 
                        // Eight byte date format
                        // 8 = <MSB, ..., LSB>
+                       // 128
                        Comm.Append ((byte) 9);
                
                        // notify of use db
+                       // 129
                        Comm.Append ((byte) 1);
 
                        // disallow dump/load and bulk insert
+                       // 130
                        Comm.Append ((byte) 1);
 
                        // sql interface type
+                       // 131
                        Comm.Append ((byte) 0);
 
                        // type of network connection
+                       // 132
                        Comm.Append ((byte) 0);
 
-
                        // spare [7]
+                       // 133-139
                        Comm.Append (empty, 7, pad);
+
                        // appname
+                       // 140-170
                        tmp = Comm.Append (connectionParameters.ApplicationName, 30, pad);
                        Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
                        // server name
+                       // 171-201
                        tmp = Comm.Append (DataSource, 30, pad);
                        Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
                        // remote passwords
+                       // 202-457      
                        Comm.Append (empty, 2, pad);
-                       tmp = Comm.Append (connectionParameters.Password, 253, pad);
+                       tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 253, pad);
                        Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
 
                        // tds version
-                       Comm.Append ((byte) (((byte) Version) / 10));
-                       Comm.Append ((byte) (((byte) Version) % 10));
+                       // 458-461
+                       Comm.Append ((byte) 5);
+                       Comm.Append ((byte) 0);
                        Comm.Append ((byte) 0);
                        Comm.Append ((byte) 0);
 
                        // prog name
+                       // 462-472
                        tmp = Comm.Append (connectionParameters.ProgName, 10, pad);
                        Comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
 
                        // prog version
+                       // 473-476
                        Comm.Append ((byte) 6);
-
-                       // Tell the server we can handle SQLServer version 6
                        Comm.Append ((byte) 0);
-
-                       // Send zero to tell the server we can't handle any other version
                        Comm.Append ((byte) 0);
                        Comm.Append ((byte) 0);
 
                        // auto convert short
+                       // 477
                        Comm.Append ((byte) 0);
 
                        // type of flt4
+                       // 478
                        Comm.Append ((byte) 0x0d);
 
                        // type of date4
+                       // 479
                        Comm.Append ((byte) 0x11);
 
                        // language
+                       // 480-510
                        tmp = Comm.Append (Language, 30, pad);
                        Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
                        // notify on lang change
+                       // 511
                        Comm.Append ((byte) 1);
 
                        // security label hierarchy
+                       // 512-513
                        Comm.Append ((short) 0);
 
                        // security components
+                       // 514-521
                        Comm.Append (empty, 8, pad);
 
                        // security spare
+                       // 522-523
                        Comm.Append ((short) 0);
 
                        // security login role
+                       // 524
                        Comm.Append ((byte) 0);
 
                        // charset
+                       // 525-555
                        tmp = Comm.Append (Charset, 30, pad);
                        Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
 
                        // notify on charset change
+                       // 556
                        Comm.Append ((byte) 1);
 
                        // length of tds packets
-                       tmp = Comm.Append (PacketSize.ToString (), 6, pad);
-                       Comm.Append ((byte) 3);
+                       // 557-563
+                       tmp = Comm.Append (this.packetSize.ToString (), 6, pad);
+                       Comm.Append ((byte) (tmp.Length < 6 ? tmp.Length : 6));
 
-                       // pad out to a longword
                        Comm.Append (empty, 8, pad);
+                       // Padding...
+                       // 564-567
+                       //Comm.Append (empty, 4, pad);
+
+                       // Capabilities
+                       Comm.Append ((byte) TdsPacketSubType.Capability);
+                       Comm.Append ((short) 20);
+                       Comm.Append ((byte) 0x01); // TDS_CAP_REQUEST
+                       Comm.Append (capabilityRequest);
+                       Comm.Append ((byte) 0x02);
+                       Comm.Append (capabilityResponse);
 
                        Comm.SendPacket ();
 
-                       TdsPacketResult result;
-                       bool done = false;
-                       while (!done) {
-                               result = ProcessSubPacket ();
-                               done = (result is TdsPacketEndTokenResult);
-                       }
+                       MoreResults = true;
+                       SkipToEnd ();
+
                        return IsConnected;
                }
 
-               protected override TdsPacketColumnInfoResult ProcessColumnInfo ()
+               public override void ExecPrepared (string id, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
                {
-                       byte precision;
-                       byte scale;
-                       int totalLength = Comm.GetTdsShort ();
-                       int bytesRead = 0;
-
-                       TdsPacketColumnInfoResult result = new TdsPacketColumnInfoResult ();
-
-                       while (bytesRead < totalLength) {
-                               scale = 0;
-                               precision = 0;
-
-                               int bufLength = -1;
-                               //int dispSize = -1;
-                               byte[] flagData = new byte[4];
-                               for (int i = 0; i < 4; i += 1) {
-                                       flagData[i] = Comm.GetByte ();
-                                       bytesRead += 1;
+                       Parameters = parameters;
+                       bool hasParameters = (Parameters != null && Parameters.Count > 0);
+
+                       Comm.StartPacket (TdsPacketType.Normal);
+
+                       Comm.Append ((byte) TdsPacketSubType.Dynamic);
+                       Comm.Append ((short) (id.Length + 5));
+                       Comm.Append ((byte) 0x02);                  // TDS_DYN_EXEC
+                       Comm.Append ((byte) (hasParameters ? 0x01 : 0x00));
+                       Comm.Append ((byte) id.Length);
+                       Comm.Append (id);
+                       Comm.Append ((short) 0);
+
+                       if (hasParameters) {
+                               SendParamFormat ();
+                               SendParams ();
+                       }
+
+                       MoreResults = true;
+                       Comm.SendPacket ();
+                       CheckForData (timeout);
+                       if (!wantResults)
+                               SkipToEnd ();
+               }
+
+               public override void Execute (string sql, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
+               {
+                       Parameters = parameters;
+                       string ex = BuildExec (sql);
+                       ExecuteQuery (ex, timeout, wantResults);
+               }
+
+               public override void ExecProc (string commandText, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
+               {
+                       Parameters = parameters;
+                       ExecuteQuery (BuildProcedureCall (commandText), timeout, wantResults);
+               }
+
+               private string BuildProcedureCall (string procedure)
+               {
+                       string exec = String.Empty;
+
+                       StringBuilder declare = new StringBuilder ();
+                       StringBuilder select = new StringBuilder ();
+                       StringBuilder set = new StringBuilder ();
+                       
+                       int count = 0;
+                       if (Parameters != null) {
+                               foreach (TdsMetaParameter p in Parameters) {
+                                       if (p.Direction != TdsParameterDirection.Input) {
+
+                                               if (count == 0)
+                                                       select.Append ("select ");
+                                               else
+                                                       select.Append (", ");
+                                               select.Append (p.ParameterName);
+                                                       
+                                               declare.Append (String.Format ("declare {0}\n", p.Prepare ()));
+
+                                               if (p.Direction != TdsParameterDirection.ReturnValue) {
+                                                       if( p.Direction == TdsParameterDirection.InputOutput )
+                                                               set.Append (String.Format ("set {0}\n", FormatParameter(p)));
+                                                       else
+                                               set.Append (String.Format ("set {0}=NULL\n", p.ParameterName));
+                                               }
+                                       
+                                               count += 1;
+                                       }
+                                       
+                                       if (p.Direction == TdsParameterDirection.ReturnValue)
+                                               exec = p.ParameterName + "=";
                                }
-                               bool nullable = (flagData[2] & 0x01) > 0;
-                               bool caseSensitive = (flagData[2] & 0x02) > 0;
-                               bool writable = (flagData[2] & 0x0c) > 0;
-                               bool autoIncrement = (flagData[2] & 0x10) > 0;
+                       }
+                       exec = "exec " + exec;
+
+                       string sql = String.Format ("{0}{1}{2}{3} {4}\n{5}", declare.ToString (),
+                               set.ToString (),
+                               exec, procedure,
+                               BuildParameters (), select.ToString ());
+                       return sql;
+               }
+
+               private string BuildParameters ()
+               {
+                       if (Parameters == null || Parameters.Count == 0)
+                               return String.Empty;
+
+                       StringBuilder result = new StringBuilder ();
+                       foreach (TdsMetaParameter p in Parameters) {
+                               if (p.Direction != TdsParameterDirection.ReturnValue) {
+                               if (result.Length > 0)
+                                       result.Append (", ");
+                                       if (p.Direction == TdsParameterDirection.InputOutput)
+                                               result.Append (String.Format("{0}={0} output", p.ParameterName));
+                                       else
+                               result.Append (FormatParameter (p));
+                       }
+                       }
+                       return result.ToString ();
+               }
+
+
+               private string FormatParameter (TdsMetaParameter parameter)
+               {
+                       if (parameter.Direction == TdsParameterDirection.Output)
+                               return String.Format ("{0} output", parameter.ParameterName);
+               
+                       if (parameter.Value == null || parameter.Value == DBNull.Value)
+                               return "NULL";
+               
+                       switch (parameter.TypeName) {
+                       case "smalldatetime":
+                       case "datetime":
+                               DateTime d = (DateTime)parameter.Value;
+                               return String.Format(System.Globalization.CultureInfo.InvariantCulture, 
+                                                    "'{0:MMM dd yyyy hh:mm:ss tt}'", d );
+                       case "bigint":
+                       case "decimal":
+                       case "float":
+                       case "int":
+                       case "money":
+                       case "real":
+                       case "smallint":
+                       case "smallmoney":
+                       case "tinyint":
+                               return parameter.Value.ToString ();
+                       case "nvarchar":
+                       case "nchar":
+                               return String.Format ("N'{0}'", parameter.Value.ToString ().Replace ("'", "''"));
+                       case "uniqueidentifier":
+                               return String.Format ("0x{0}", ((Guid) parameter.Value).ToString ("N"));
+                       case "bit":
+                               if (parameter.Value.GetType () == typeof (bool))
+                                       return (((bool) parameter.Value) ? "0x1" : "0x0");
+                               return parameter.Value.ToString ();
+                       case "image":
+                       case "binary":
+                       case "varbinary":
+                               return String.Format ("0x{0}", BitConverter.ToString ((byte[]) parameter.Value).Replace ("-", string.Empty).ToLower ());
+                       default:
+                               return String.Format ("'{0}'", parameter.Value.ToString ().Replace ("'", "''"));
+                       }
+               }
+
+               public override string Prepare (string sql, TdsMetaParameterCollection parameters)
+               {
+                       Parameters = parameters;
 
-                               string tableName = String.Empty;
-                               TdsColumnType columnType = (TdsColumnType) Comm.GetByte ();
+                       Random rand = new Random ();
+                       StringBuilder idBuilder = new StringBuilder ();
+                       for (int i = 0; i < 25; i += 1)
+                               idBuilder.Append ((char) (rand.Next (26) + 65));
+                       string id = idBuilder.ToString ();
 
-                               bytesRead += 1;
+                       //StringBuilder declare = new StringBuilder ();
+
+               
+                       sql = String.Format ("create proc {0} as\n{1}", id, sql);
+                       short len = (short) ((id.Length) + sql.Length + 5);
+
+                       Comm.StartPacket (TdsPacketType.Normal);
+                       Comm.Append ((byte) TdsPacketSubType.Dynamic);
+                       Comm.Append (len);
+                       Comm.Append ((byte) 0x1); // PREPARE
+                       Comm.Append ((byte) 0x0); // UNUSED
+                       Comm.Append ((byte) id.Length);
+                       Comm.Append (id);
+                       Comm.Append ((short) sql.Length);
+                       Comm.Append (sql);
+
+                       Comm.SendPacket ();
+                       MoreResults = true;
+                       SkipToEnd ();
+
+                       return id;
+               }
+
+               protected override void ProcessColumnInfo ()
+               {
+                       isSelectQuery = true; 
+                       /*int totalLength = */Comm.GetTdsShort ();
+                       int count = Comm.GetTdsShort ();
+                       for (int i = 0; i < count; i += 1) {
+                               string columnName = Comm.GetString (Comm.GetByte ());
+                               int status = Comm.GetByte ();
+                               bool hidden = (status & 0x01) > 0;
+                               bool isKey = (status & 0x02) > 0;
+                               bool isRowVersion = (status & 0x04) > 0;
+                               bool isUpdatable = (status & 0x10) > 0;
+                               bool allowDBNull = (status & 0x20) > 0;
+                               bool isIdentity = (status & 0x40) > 0;
+
+                               Comm.Skip (4); // User type
+
+                               byte type = Comm.GetByte ();
+                               bool isBlob = (type == 0x24);
+
+                               TdsColumnType columnType = (TdsColumnType) type;
+                               int bufLength = 0;
+
+                               byte precision = 0;
+                               byte scale = 0;
 
                                if (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image) {
-                                       Comm.Skip (4);
-                                       bytesRead += 4;
-
-                                       int tableNameLength = Comm.GetTdsShort ();
-                                       bytesRead += 2;
-                                       tableName = Comm.GetString (tableNameLength);
-                                       bytesRead += tableNameLength;
-                                       bufLength = 2 << 31 - 1;
+                                       bufLength = Comm.GetTdsInt ();
+                                       Comm.Skip (Comm.GetTdsShort ());
                                }
-                               else if (columnType == TdsColumnType.Decimal || columnType == TdsColumnType.Numeric) {
+                               else if (IsFixedSizeColumn (columnType))
+                                       bufLength = LookupBufferSize (columnType);
+                               else
+                                       //bufLength = Comm.GetTdsShort ();
                                        bufLength = Comm.GetByte ();
-                                       bytesRead += 1;
+
+                               if (columnType == TdsColumnType.Decimal || columnType == TdsColumnType.Numeric) {
                                        precision = Comm.GetByte ();
-                                       bytesRead += 1;
                                        scale = Comm.GetByte ();
-                                       bytesRead += 1;
                                }
-                               else if (IsFixedSizeColumn (columnType))
-                                       bufLength = LookupBufferSize (columnType);
-                               else {
-                                       bufLength = (int) Comm.GetByte () & 0xff;
-                                       bytesRead += 1;
+
+                               Comm.Skip (Comm.GetByte ()); // Locale
+                               if (isBlob)
+                                       Comm.Skip (Comm.GetTdsShort ()); // Class ID
+
+                               TdsDataColumn col = new TdsDataColumn ();
+                               Columns.Add (col);
+#if NET_2_0
+                               col.ColumnType = columnType;
+                               col.ColumnName = columnName;
+                               col.IsIdentity = isIdentity;
+                               col.IsRowVersion = isRowVersion;
+                               col.ColumnType = columnType;
+                               col.ColumnSize = bufLength;
+                               col.NumericPrecision = precision;
+                               col.NumericScale = scale;
+                               col.IsReadOnly = !isUpdatable;
+                               col.IsKey = isKey;
+                               col.AllowDBNull = allowDBNull;
+                               col.IsHidden = hidden;
+#else
+                               col ["ColumnType"] = columnType;
+                               col ["ColumnName"] = columnName;
+                               col ["IsIdentity"] = isIdentity;
+                               col ["IsRowVersion"] = isRowVersion;
+                               col ["ColumnType"] = columnType;
+                               col ["ColumnSize"] = bufLength;
+                               col ["NumericPrecision"] = precision;
+                               col ["NumericScale"] = scale;
+                               col ["IsReadOnly"] = !isUpdatable;
+                               col ["IsKey"] = isKey;
+                               col ["AllowDBNull"] = allowDBNull;
+                               col ["IsHidden"] = hidden;
+#endif
+                       }
+               }
+
+               private void SendParamFormat ()
+               {
+                       Comm.Append ((byte) TdsPacketSubType.ParamFormat);
+
+                       int len = 2 + (8 * Parameters.Count);
+                       TdsColumnType metaType;
+                       foreach (TdsMetaParameter p in Parameters) {
+                               metaType = p.GetMetaType ();
+                               if (!IsFixedSizeColumn (metaType))
+                                       len += 1;
+                               if (metaType == TdsColumnType.Numeric || metaType == TdsColumnType.Decimal)
+                                       len += 2;
+                       }
+
+                       Comm.Append ((short) len);
+                       Comm.Append ((short) Parameters.Count);
+
+                       foreach (TdsMetaParameter p in Parameters) {
+                               string locale = String.Empty;
+                               string parameterName = String.Empty;
+                               int userType = 0;
+
+                               byte status = 0x00;
+                               if (p.IsNullable)
+                                       status |= 0x20;
+                               if (p.Direction == TdsParameterDirection.Output)
+                                       status |= 0x01;
+
+                               metaType = p.GetMetaType ();
+
+                               Comm.Append ((byte) parameterName.Length);
+                               Comm.Append (parameterName);
+                               Comm.Append (status);
+                               Comm.Append (userType);
+                               Comm.Append ((byte) metaType);
+
+                               if (!IsFixedSizeColumn (metaType))
+                                       Comm.Append ((byte) p.Size);         // MAXIMUM SIZE
+                               if (metaType == TdsColumnType.Numeric || metaType == TdsColumnType.Decimal) {
+                                       Comm.Append (p.Precision);
+                                       Comm.Append (p.Scale);
                                }
+                               Comm.Append ((byte) locale.Length);
+                               Comm.Append (locale);
+                       }
+               }
 
-                               int index = result.Add (new TdsSchemaInfo ());
-                               result[index]["NumericPrecision"] = precision;
-                               result[index]["NumericScale"] = scale;
-                               result[index]["ColumnSize"] = bufLength;
-                               result[index]["ColumnName"] = ColumnNames[index];
-                               result[index]["BaseTableName"] = tableName;
-                               result[index]["AllowDBNull"] = nullable;
-                               result[index]["IsReadOnly"] = !writable;
-                               result[index]["ColumnType"] = columnType;
+               private void SendParams ()
+               {
+                       Comm.Append ((byte) TdsPacketSubType.Parameters);
+
+                       TdsColumnType metaType;
+                       foreach (TdsMetaParameter p in Parameters) {
+                               metaType = p.GetMetaType ();
+                               bool isNull = (p.Value == DBNull.Value || p.Value == null);
+                               if (!IsFixedSizeColumn (metaType))
+                                       Comm.Append ((byte) p.GetActualSize ());
+                               if (!isNull)
+                                       Comm.Append (p.Value);
                        }
+               }
+
+               public override void Unprepare (string statementId)
+               {
+                       Comm.StartPacket (TdsPacketType.Normal);
+                       Comm.Append ((byte) TdsPacketSubType.Dynamic);
+                       Comm.Append ((short) (3 + statementId.Length));
+                       Comm.Append ((byte) 0x04);
+                       Comm.Append ((byte) 0x00);
+                       Comm.Append ((byte) statementId.Length);
+                       Comm.Append (statementId);
+                       //Comm.Append ((short) 0);
+
+                       MoreResults = true;
+                       Comm.SendPacket ();
+                       SkipToEnd ();
+               }
+
+               protected override bool IsValidRowCount (byte status, byte op)
+               {
+                       if (isSelectQuery)
+                               return (isSelectQuery = false);
+
+                       // TODO : Need to figure out how to calculate rowcount inside stored 
+                       // procedures. For now, Ignoring RowCount if they are returned by 
+                       // statements executing inside a StoredProcedure
 
-                       //int skipLength = totalLength - bytesRead;
-                       //if (skipLength != 0)
-                               //throw new TdsException ("skipping");
+                       if (((status & (byte)0x40) != 0) || ((status & (byte)0x10) == 0))
+                               return false;
 
-                       return result;
+                       return true;
                }
 
                #endregion // Methods