Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds / TdsMetaParameter.cs
index 5f6bb481843af4d81fa11d9595daebacc3e9c4da..8b704455cb3cb1cd1c77b378c82586f079ebd7a3 100644 (file)
@@ -33,8 +33,15 @@ using System;
 using System.Text;
 
 namespace Mono.Data.Tds {
+       public delegate object FrameworkValueGetter (object rawValue, ref bool updated);
+
        public class TdsMetaParameter
        {
+               #region Static 
+               public const int maxVarCharCharacters =  2147483647; // According to MS, max size is 2GB, 1 Byte Characters
+               public const int maxNVarCharCharacters = 1073741823; // According to MS, max size is 2GB, 2 Byte Characters
+               #endregion
+
                #region Fields
 
                TdsParameterDirection direction = TdsParameterDirection.Input;
@@ -47,6 +54,9 @@ namespace Mono.Data.Tds {
                bool isNullable;
                object value;
                bool isVariableSizeType;
+               FrameworkValueGetter frameworkValueGetter;
+               object rawValue;
+               bool isUpdated;
 
                #endregion // Fields
 
@@ -55,6 +65,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 +89,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 +122,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 +168,8 @@ namespace Mono.Data.Tds {
                public int Size {
                        get { return GetSize (); }
                        set {
-                               size = value; 
+                               size = value;
+                               isUpdated = true;
                                isSizeSet = true;
                        }
                }
@@ -133,10 +180,110 @@ namespace Mono.Data.Tds {
                        set { isVariableSizeType = value; }
                }
 
+               public bool IsVarNVarCharMax
+               {
+                       get { return (TypeName == "ntext" && size >= maxNVarCharCharacters); }
+               }
+
+               public bool IsVarCharMax
+               {
+                       get { return (TypeName == "text" && size >= maxVarCharCharacters); }
+               }
+
+               public bool IsAnyVarCharMax
+               {
+                       get { return IsVarNVarCharMax || IsVarCharMax; }
+               }
+
+               public bool IsNonUnicodeText
+               {
+                       get {
+                               TdsColumnType colType = GetMetaType();
+                               return (colType == TdsColumnType.VarChar ||
+                                       colType == TdsColumnType.BigVarChar ||
+                                       colType == TdsColumnType.Text ||
+                                       colType == TdsColumnType.Char ||
+                                       colType == TdsColumnType.BigChar);
+                       }
+               }
+
+               public bool IsMoneyType
+               {
+                       get {
+                               TdsColumnType colType = GetMetaType();
+                               return (colType == TdsColumnType.Money ||
+                                       colType == TdsColumnType.MoneyN ||
+                                       colType == TdsColumnType.Money4 ||
+                                       colType == TdsColumnType.SmallMoney);
+                       }
+               }
+
+               public bool IsDateTimeType
+               {
+                       get {
+                               TdsColumnType colType = GetMetaType();
+                               return (colType == TdsColumnType.DateTime ||
+                                       colType == TdsColumnType.DateTime4 ||
+                                       colType == TdsColumnType.DateTimeN);
+                       }
+               }
+
+               public bool IsTextType
+               {
+                       get {
+                               TdsColumnType colType = GetMetaType();
+                               return (colType == TdsColumnType.VarChar ||
+                                       colType == TdsColumnType.BigVarChar ||
+                                       colType == TdsColumnType.BigChar ||
+                                       colType == TdsColumnType.Char ||
+                                       colType == TdsColumnType.BigNVarChar || 
+                                       colType == TdsColumnType.NChar ||
+                                       colType == TdsColumnType.Text ||
+                                       colType == TdsColumnType.NText);
+                       }
+               }
+
+               public bool IsDecimalType
+               {
+                       get {
+                               TdsColumnType colType = GetMetaType();
+                               return (colType == TdsColumnType.Decimal ||
+                                       colType == TdsColumnType.Numeric);
+                       }
+               }
+
                #endregion // Properties
 
                #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 +295,7 @@ namespace Mono.Data.Tds {
                                }
                                
                                if (size > 8000) {
-                                       typeName = "image";
+                                       typeName = "varbinary(max)";
                                }
                        }
                        
@@ -159,9 +306,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 +319,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":
@@ -194,7 +343,12 @@ namespace Mono.Data.Tds {
 
                        switch (Value.GetType ().ToString ()) {
                        case "System.String":
-                               return ((string) value).Length;
+                               int len = ((string)value).Length;
+                               if (TypeName == "nvarchar" || TypeName == "nchar" 
+                                   || TypeName == "ntext"
+                                   || TypeName == "xml")
+                                       len *= 2;
+                               return len ;    
                        case "System.Byte[]":
                                return ((byte[]) value).Length;
                        }
@@ -203,45 +357,94 @@ namespace Mono.Data.Tds {
 
                private int GetSize ()
                {
-                       if (IsNullable) {
-                               switch (TypeName) {
-                               case "bigint":
-                                       return 8;
-                               case "datetime":
-                                       return 8;
-                               case "float":
-                                       return 8;
-                               case "int":
-                                       return 4;
-                               case "real":
-                                       return 4;
-                               case "smalldatetime":
-                                       return 4;
-                               case "smallint":
-                                       return 2;
-                               case "tinyint":
-                                       return 1;
-                               }
+                       switch (TypeName) {
+                       case "decimal":
+                               return 17;
+                       case "uniqueidentifier":
+                               return 16;
+                       case "bigint":
+                       case "datetime":
+                       case "float":
+                       case "money":
+                               return 8;
+                       case "int":
+                       case "real":
+                       case "smalldatetime":
+                       case "smallmoney":
+                               return 4;
+                       case "smallint":
+                               return 2;
+                       case "tinyint":
+                       case "bit":
+                               return 1;
+                       /*
+                       case "nvarchar" :
+                       */
+                       case "nchar" :
+                       case "ntext" :
+                               return size*2 ;
                        }
                        return size;
                }
 
+               internal byte[] GetBytes ()
+               {
+                       byte[] result = {};
+                       if (Value == DBNull.Value || Value == null)
+                               return result;
+
+                       switch (TypeName)
+                       {
+                               case "nvarchar" :
+                               case "nchar" :
+                               case "ntext" :
+                               case "xml" :
+                                       return Encoding.Unicode.GetBytes ((string)Value);
+                               case "varchar" :
+                               case "char" :
+                               case "text" :
+                                       return Encoding.Default.GetBytes ((string)Value);
+                               default :
+                                       return ((byte[]) Value);
+                       }
+               }
+
                internal TdsColumnType GetMetaType ()
                {
                        switch (TypeName) {
                        case "binary":
-                               return TdsColumnType.Binary;
+                               return TdsColumnType.BigBinary;
                        case "bit":
+                               if (IsNullable)
+                                       return TdsColumnType.BitN;
                                return TdsColumnType.Bit;
+                       case "bigint":
+                               if (IsNullable)
+                                       return TdsColumnType.IntN ;
+                               return TdsColumnType.BigInt;
                        case "char":
-                               return TdsColumnType.Char;
+                               return TdsColumnType.BigChar;
+                       case "money":
+                               if (IsNullable)
+                                       return TdsColumnType.MoneyN;
+                               return TdsColumnType.Money;
+                       case "smallmoney":
+                               if (IsNullable)
+                                       return TdsColumnType.MoneyN ;
+                               return TdsColumnType.SmallMoney;
                        case "decimal":
                                return TdsColumnType.Decimal;
                        case "datetime":
                                if (IsNullable)
                                        return TdsColumnType.DateTimeN;
                                return TdsColumnType.DateTime;
+                       case "smalldatetime":
+                               if (IsNullable)
+                                       return TdsColumnType.DateTimeN;
+                               return TdsColumnType.DateTime4;
                        case "float":
+                               if (IsNullable)
+                                       return TdsColumnType.FloatN ;
                                return TdsColumnType.Float8;
                        case "image":
                                return TdsColumnType.Image;
@@ -255,9 +458,12 @@ namespace Mono.Data.Tds {
                                return TdsColumnType.NChar;
                        case "ntext":
                                return TdsColumnType.NText;
+                       case "xml":
                        case "nvarchar":
-                               return TdsColumnType.NVarChar;
+                               return TdsColumnType.BigNVarChar;
                        case "real":
+                               if (IsNullable)
+                                       return TdsColumnType.FloatN ;
                                return TdsColumnType.Real;
                        case "smallint":
                                if (IsNullable)
@@ -272,11 +478,39 @@ namespace Mono.Data.Tds {
                        case "uniqueidentifier":
                                return TdsColumnType.UniqueIdentifier;
                        case "varbinary":
-                               return TdsColumnType.VarBinary;
+                               return TdsColumnType.BigVarBinary;
                        case "varchar":
-                               return TdsColumnType.VarChar;
+                               return TdsColumnType.BigVarChar;
                        default:
-                               throw new NotSupportedException ();
+                               throw new NotSupportedException ("Unknown Type : " + TypeName);
+                       }
+               }
+
+               public void CalculateIsVariableType()
+               {
+                       switch (GetMetaType ()) {
+                               case TdsColumnType.UniqueIdentifier:
+                               case TdsColumnType.BigVarChar:
+                               case TdsColumnType.BigVarBinary:
+                               case TdsColumnType.IntN:
+                               case TdsColumnType.Text:
+                               case TdsColumnType.FloatN:
+                               case TdsColumnType.BigNVarChar:
+                               case TdsColumnType.NText:
+                               case TdsColumnType.Image:
+                               case TdsColumnType.Decimal:
+                               case TdsColumnType.BigBinary:
+                               case TdsColumnType.DateTimeN:
+                               case TdsColumnType.MoneyN:
+                               case TdsColumnType.BitN:
+                               case TdsColumnType.Char:
+                               case TdsColumnType.BigChar:
+                               case TdsColumnType.NChar:
+                                       IsVariableSizeType = true;
+                                       break;
+                               default:
+                                       IsVariableSizeType = false;
+                               break;
                        }
                }