New tests.
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds.Protocol / Tds70.cs
index 50322fb814740eda78ed564374e57f86fd65eaab..57fb0914645e385fc2638e012dba459829845478 100644 (file)
@@ -243,6 +243,7 @@ namespace Mono.Data.Tds.Protocol
 
                        //Comm.Append (empty, 3, pad);
                        //byte[] version = {0x00, 0x0, 0x0, 0x71};
+                       //Console.WriteLine ("Version: {0}", ClientVersion[3]);
                        Comm.Append (ClientVersion); // TDS Version 7
                        Comm.Append ((int)this.PacketSize); // Set the Block Size
                        Comm.Append (empty, 3, pad);
@@ -384,14 +385,17 @@ namespace Mono.Data.Tds.Protocol
 
                        // Set "reset-connection" bit for the next message packet
                        Comm.ResetConnection = true;
-
+                       base.Reset ();
                        return true;
                }
 
                public override void ExecPrepared (string commandText, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
                {
                        Parameters = parameters;
-                       ExecuteQuery (BuildPreparedQuery (commandText), timeout, wantResults);
+                       if (Parameters != null && Parameters.Count > 0)
+                               ExecRPC (TdsRpcProcId.ExecuteSql, commandText, parameters, timeout, wantResults);
+                       else
+                               ExecuteQuery (BuildPreparedQuery (commandText), timeout, wantResults);
                }
                        
                public override void ExecProc (string commandText, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
@@ -400,16 +404,8 @@ namespace Mono.Data.Tds.Protocol
                        ExecRPC (commandText, parameters, timeout, wantResults);
                }
 
-               protected override void ExecRPC (string rpcName, TdsMetaParameterCollection parameters, 
-                                                int timeout, bool wantResults)
+               private void WriteRpcParameterInfo (TdsMetaParameterCollection parameters)
                {
-                       // clean up
-                       InitExec ();
-                       Comm.StartPacket (TdsPacketType.RPC);
-
-                       Comm.Append ( (short) rpcName.Length);
-                       Comm.Append (rpcName);
-                       Comm.Append ( (short) 0); //no meta data
                        if (parameters != null) {
                                foreach (TdsMetaParameter param in parameters) {
                                        if (param.Direction == TdsParameterDirection.ReturnValue) 
@@ -429,6 +425,66 @@ namespace Mono.Data.Tds.Protocol
                                        WriteParameterInfo (param);
                                }
                        }
+               }
+               
+               private void WritePreparedParameterInfo (TdsMetaParameterCollection parameters)
+               {
+                       if (parameters == null)
+                               return;
+                       
+                       string param = BuildPreparedParameters ();
+                       Comm.Append ((byte) 0x00); // no param meta data name
+                       Comm.Append ((byte) 0x00); // no status flags
+                       
+                       // Type_info - parameter info
+                       WriteParameterInfo (new TdsMetaParameter ("prep_params", 
+                                                                 param.Length > 4000 ? "ntext" : "nvarchar", 
+                                                                 param));
+               }
+               
+               private void ExecRPC (TdsRpcProcId rpcId, string sql, 
+                                     TdsMetaParameterCollection parameters, 
+                                     int timeout, bool wantResults)
+               {
+                       // clean up
+                       InitExec ();
+                       Comm.StartPacket (TdsPacketType.RPC);
+                       
+                       Comm.Append ((ushort) 0xFFFF);
+                       Comm.Append ((ushort) rpcId);
+                       Comm.Append ((short) 0x02); // no meta data
+                       
+                       Comm.Append ((byte) 0x00); // no param meta data name
+                       Comm.Append ((byte) 0x00); // no status flags
+                       
+                       // Write sql as a parameter value - UCS2
+                       TdsMetaParameter param = new TdsMetaParameter ("sql", 
+                                                                      sql.Length > 4000 ? "ntext":"nvarchar",
+                                                                      sql);            
+                       WriteParameterInfo (param);
+                       
+                       // Write Parameter infos - name and type
+                       WritePreparedParameterInfo (parameters);
+
+                       // Write parameter/value info
+                       WriteRpcParameterInfo (parameters);
+                       Comm.SendPacket ();
+                       CheckForData (timeout);
+                       if (!wantResults)
+                               SkipToEnd ();
+               }
+               
+               protected override void ExecRPC (string rpcName, TdsMetaParameterCollection parameters, 
+                                                int timeout, bool wantResults)
+               {
+                       // clean up
+                       InitExec ();
+                       Comm.StartPacket (TdsPacketType.RPC);
+
+                       Comm.Append ( (short) rpcName.Length);
+                       Comm.Append (rpcName);
+                       Comm.Append ( (short) 0); //no meta data
+                       WriteRpcParameterInfo (parameters);
                        Comm.SendPacket ();
                        CheckForData (timeout);
                        if (!wantResults)
@@ -445,18 +501,57 @@ namespace Mono.Data.Tds.Protocol
                        TdsColumnType colType = param.GetMetaType ();
                        param.IsNullable = false;
 
-                       Comm.Append ((byte)colType); // type
-
+                       bool partLenType = false;
                        int size = param.Size;
-                       if (size == 0)
+                       if (size < 1) {
+                               if (size < 0)
+                                       partLenType = true;
                                size = param.GetActualSize ();
+                       }
 
-                       /*
-                         If column type is SqlDbType.NVarChar the size of parameter is multiplied by 2
-                         FIXME: Need to check for other types
+                       // Change colType according to the following table
+                       /* 
+                        * Original Type        Maxlen          New Type 
+                        * 
+                        * NVarChar             4000 UCS2       NText
+                        * BigVarChar           8000 ASCII      Text
+                        * BigVarBinary         8000 bytes      Image
+                        * 
                         */
-                       if (colType == TdsColumnType.BigNVarChar)
-                               size <<= 1;
+                       TdsColumnType origColType = colType;
+                       if (colType == TdsColumnType.BigNVarChar) {
+                               // param.GetActualSize() returns len*2
+                               if (size == param.Size)
+                                       size <<= 1;
+                               if ((size >> 1) > 4000)
+                                       colType = TdsColumnType.NText;
+                       } else if (colType == TdsColumnType.BigVarChar) {
+                               if (size > 8000)
+                                       colType = TdsColumnType.Text;   
+                       } else if (colType == TdsColumnType.BigVarBinary) {
+                               if (size > 8000)
+                                       colType = TdsColumnType.Image;
+                       }
+                       // Calculation of TypeInfo field
+                       /* 
+                        * orig size value              TypeInfo field
+                        * 
+                        * >= 0 <= Maxlen               origColType + content len
+                        * > Maxlen             NewType as per above table + content len
+                        * -1           origColType + USHORTMAXLEN (0xFFFF) + content len (TDS 9)
+                        * 
+                        */
+                       // Write updated colType, iff partLenType == false
+                       if (TdsVersion > TdsVersion.tds81 && partLenType) {
+                               Comm.Append ((byte)origColType);
+                               Comm.Append ((short)-1);
+                       } else if (ServerTdsVersion > TdsVersion.tds70 
+                                  && origColType == TdsColumnType.Decimal) {
+                               Comm.Append ((byte)TdsColumnType.Numeric);
+                       } else {
+                               Comm.Append ((byte)colType);
+                       }
+
                        if (IsLargeType (colType))
                                Comm.Append ((short)size); // Parameter size passed in SqlParameter
                        else if (IsBlobType (colType))
@@ -466,17 +561,28 @@ namespace Mono.Data.Tds.Protocol
 
                        // Precision and Scale are non-zero for only decimal/numeric
                        if ( param.TypeName == "decimal" || param.TypeName == "numeric") {
-                               Comm.Append ((param.Precision !=0 ) ? param.Precision : (byte) 28);
+                               Comm.Append ((param.Precision !=0 ) ? param.Precision : (byte) 29);
                                Comm.Append (param.Scale);
+                               // Convert the decimal value according to Scale
+                               if (param.Value != null && param.Value != DBNull.Value &&
+                                   ((decimal)param.Value) != Decimal.MaxValue && 
+                                   ((decimal)param.Value) != Decimal.MinValue) {
+                                       decimal expo = new Decimal (System.Math.Pow (10, (double)param.Scale));
+                                       int pVal = (int)(((decimal)param.Value) * expo);
+                                       param.Value = (decimal)pVal;                            
+                               }
                        }
 
+                       
+                       /* VARADHAN: TDS 8 Debugging */
                        /*
-                        * VARADHAN: TDS 8 Debugging *
                        if (Collation != null) {
                                Console.WriteLine ("Collation is not null");
                                Console.WriteLine ("Column Type: {0}", colType);
                                Console.WriteLine ("Collation bytes: {0} {1} {2} {3} {4}", Collation[0], Collation[1], Collation[2],
                                                   Collation[3], Collation[4]);
+                       } else {
+                               Console.WriteLine ("Collation is null");
                        }
                        */
                        
@@ -487,12 +593,21 @@ namespace Mono.Data.Tds.Protocol
                             colType == TdsColumnType.NVarChar || colType == TdsColumnType.Text ||
                             colType == TdsColumnType.NText))
                                Comm.Append (Collation);
-                       
-                       size = param.GetActualSize ();
+
+                       // LAMESPEC: size should be 0xFFFF for any bigvarchar, bignvarchar and bigvarbinary 
+                       // types if param value is NULL
+                       if ((colType == TdsColumnType.BigVarChar || 
+                            colType == TdsColumnType.BigNVarChar ||
+                            colType == TdsColumnType.BigVarBinary) && 
+                           (param.Value == null || param.Value == DBNull.Value))
+                               size = -1;
+                       else
+                               size = param.GetActualSize ();
+
                        if (IsLargeType (colType))
-                               Comm.Append ((short)size);
+                               Comm.Append ((short)size); 
                        else if (IsBlobType (colType))
-                               Comm.Append (size);
+                               Comm.Append (size); 
                        else
                                Comm.Append ((byte)size);
                        
@@ -560,9 +675,14 @@ namespace Mono.Data.Tds.Protocol
                {
                        Parameters = parameters;
                        string sql = commandText;
-                       if (wantResults || (Parameters != null && Parameters.Count > 0))
-                               sql = BuildExec (commandText);
-                       ExecuteQuery (sql, timeout, wantResults);
+
+                       if (Parameters != null && Parameters.Count > 0) {
+                               ExecRPC (TdsRpcProcId.ExecuteSql, commandText, parameters, timeout, wantResults);
+                       } else {
+                               if (wantResults)
+                                       sql = BuildExec (commandText);
+                               ExecuteQuery (sql, timeout, wantResults);
+                       }
                }
 
                private string FormatParameter (TdsMetaParameter parameter)
@@ -653,9 +773,8 @@ namespace Mono.Data.Tds.Protocol
                        //return ColumnValues [0].ToString ();
                }
 
-               protected override TdsDataColumnCollection ProcessColumnInfo ()
+               protected override void ProcessColumnInfo ()
                {
-                       TdsDataColumnCollection result = new TdsDataColumnCollection ();
                        int numColumns = Comm.GetTdsShort ();
                        for (int i = 0; i < numColumns; i += 1) {
                                byte[] flagData = new byte[4];
@@ -708,7 +827,7 @@ namespace Mono.Data.Tds.Protocol
                                string columnName = Comm.GetString (Comm.GetByte ());
 
                                TdsDataColumn col = new TdsDataColumn ();
-                               result.Add (col);
+                               Columns.Add (col);
 #if NET_2_0
                                col.ColumnType = columnType;
                                col.ColumnName = columnName;
@@ -720,6 +839,7 @@ namespace Mono.Data.Tds.Protocol
                                col.IsReadOnly = !writable;
                                col.AllowDBNull = nullable;
                                col.BaseTableName = tableName;
+                               col.DataTypeName = Enum.GetName (typeof (TdsColumnType), xColumnType);
 #else
                                col ["ColumnType"] = columnType;
                                col ["ColumnName"] = columnName;
@@ -731,9 +851,9 @@ namespace Mono.Data.Tds.Protocol
                                col ["IsReadOnly"] = !writable;
                                col ["AllowDBNull"] = nullable;
                                col ["BaseTableName"] = tableName;
+                               col ["DataTypeName"] = Enum.GetName (typeof (TdsColumnType), xColumnType);
 #endif
                        }
-                       return result;
                }
 
                public override void Unprepare (string statementId)