Merge pull request #214 from QuickJack/cd2c570c5543963d987f51080218715407c5d4b9
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds / TdsMetaParameter.cs
index aa18da4d9e92cb864316dcc4ae53ecfbc2cba296..aa5422df5e3bf0708cccaf425567513b8e822f3e 100644 (file)
@@ -33,6 +33,8 @@ using System;
 using System.Text;
 
 namespace Mono.Data.Tds {
+       public delegate object FrameworkValueGetter (object rawValue, ref bool updated);
+
        public class TdsMetaParameter
        {
                #region Fields
@@ -47,6 +49,9 @@ namespace Mono.Data.Tds {
                bool isNullable;
                object value;
                bool isVariableSizeType;
+               FrameworkValueGetter frameworkValueGetter;
+               object rawValue;
+               bool isUpdated;
 
                #endregion // Fields
 
@@ -55,6 +60,12 @@ namespace Mono.Data.Tds {
                {
                }
 
+               public TdsMetaParameter (string name, FrameworkValueGetter valueGetter)
+                       : this (name, String.Empty, null)
+               {
+                       frameworkValueGetter = valueGetter;
+               }
+
                public TdsMetaParameter (string name, string typeName, object value)
                {
                        ParameterName = name;
@@ -73,6 +84,16 @@ namespace Mono.Data.Tds {
                        Value = value;
                }
 
+               public TdsMetaParameter (string name, int size, bool isNullable, byte precision, byte scale, FrameworkValueGetter valueGetter)
+               {
+                       ParameterName = name;
+                       Size = size;
+                       IsNullable = isNullable;
+                       Precision = precision;
+                       Scale = scale;
+                       frameworkValueGetter = valueGetter;
+               }
+
                #region Properties
 
                public TdsParameterDirection Direction {
@@ -96,8 +117,28 @@ namespace Mono.Data.Tds {
                }
 
                public object Value {
-                       get { return value; }
-                       set { this.value = value; }
+                       get {
+                               if (frameworkValueGetter != null) {
+                                       object newValue = frameworkValueGetter (rawValue, ref isUpdated);
+                                       if (isUpdated)
+                                               value = newValue;
+                               }
+
+                               if (isUpdated) {
+                                       value = ResizeValue (value);
+                                       isUpdated = false;
+                               }
+                               return value;
+                       }
+                       set {
+                               rawValue = this.value = value;
+                               isUpdated = true;
+                       }
+               }
+
+               public object RawValue {
+                       get { return rawValue; }
+                       set { Value = value; }
                }
 
                public byte Precision {
@@ -122,7 +163,8 @@ namespace Mono.Data.Tds {
                public int Size {
                        get { return GetSize (); }
                        set {
-                               size = value; 
+                               size = value;
+                               isUpdated = true;
                                isSizeSet = true;
                        }
                }
@@ -137,6 +179,34 @@ namespace Mono.Data.Tds {
 
                #region Methods
 
+               object ResizeValue (object newValue)
+               {
+                       if (newValue == DBNull.Value || newValue == null)
+                               return newValue;
+
+                       if (!isSizeSet || size <= 0)
+                               return newValue;
+
+                       // if size is set, truncate the value to specified size
+                       string text = newValue as string;
+                       if (text != null) {
+                               if (TypeName == "nvarchar" || 
+                                   TypeName == "nchar" ||
+                                   TypeName == "xml") {
+                                       if (text.Length > size)
+                                               return text.Substring (0, size);
+                               }
+                       } else if (newValue.GetType () == typeof (byte [])) {
+                               byte [] buffer = (byte []) newValue;
+                               if (buffer.Length > size) {
+                                       byte [] tmpVal = new byte [size];
+                                       Array.Copy (buffer, tmpVal, size);
+                                       return tmpVal;
+                               }
+                       }
+                       return newValue;
+               }
+
                internal string Prepare ()
                {
                        string typeName = TypeName;
@@ -148,7 +218,7 @@ namespace Mono.Data.Tds {
                                }
                                
                                if (size > 8000) {
-                                       typeName = "image";
+                                       typeName = "varbinary(max)";
                                }
                        }
                        
@@ -159,9 +229,9 @@ namespace Mono.Data.Tds {
                        switch (typeName) {
                        case "decimal":
                        case "numeric":
-                               // msdotnet sends a default precision of 28
+                               // msdotnet sends a default precision of 29
                                result.Append (String.Format ("({0},{1})",
-                                        (Precision == (byte)0 ? (byte)28 : Precision), Scale));
+                                        (Precision == (byte)0 ? (byte)38 : Precision), Scale));
                                break;
                        case "varchar":
                        case "varbinary":
@@ -172,10 +242,12 @@ namespace Mono.Data.Tds {
                                        if (size <= 0)
                                                size = 1;
                                }
-                               result.Append (String.Format ("({0})", size));
+                               result.Append (size > 8000 ? "(max)" : String.Format ("({0})", size));
                                break;
                        case "nvarchar":
-                               result.Append (String.Format ("({0})", Size > 0 ? Size : 4000));
+                       case "xml":
+                               int paramSize = Size < 0 ? GetActualSize () / 2 : Size;
+                               result.Append (paramSize > 0 ? (paramSize > 4000 ? "(max)" : String.Format ("({0})", paramSize)) : "(4000)");
                                break;
                        case "char":
                        case "nchar":
@@ -195,7 +267,9 @@ namespace Mono.Data.Tds {
                        switch (Value.GetType ().ToString ()) {
                        case "System.String":
                                int len = ((string)value).Length;
-                               if (TypeName == "nvarchar" || TypeName == "nchar" || TypeName == "ntext")
+                               if (TypeName == "nvarchar" || TypeName == "nchar" 
+                                   || TypeName == "ntext"
+                                   || TypeName == "xml")
                                        len *= 2;
                                return len ;    
                        case "System.Byte[]":
@@ -247,6 +321,7 @@ namespace Mono.Data.Tds {
                                case "nvarchar" :
                                case "nchar" :
                                case "ntext" :
+                               case "xml" :
                                        return Encoding.Unicode.GetBytes ((string)Value);
                                case "varchar" :
                                case "char" :
@@ -267,7 +342,9 @@ namespace Mono.Data.Tds {
                                        return TdsColumnType.BitN;
                                return TdsColumnType.Bit;
                        case "bigint":
-                               return TdsColumnType.IntN;
+                               if (IsNullable)
+                                       return TdsColumnType.IntN ;
+                               return TdsColumnType.BigInt;
                        case "char":
                                return TdsColumnType.Char;
                        case "money":
@@ -304,6 +381,7 @@ namespace Mono.Data.Tds {
                                return TdsColumnType.NChar;
                        case "ntext":
                                return TdsColumnType.NText;
+                       case "xml":
                        case "nvarchar":
                                return TdsColumnType.BigNVarChar;
                        case "real":