Support the datetime2 parameter type
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlParameter.cs
index ac6c1b2c4594d859b8571e8136e81413560dc580..ddfb688b45248b850cc5828b86f75379590fca1b 100644 (file)
@@ -7,13 +7,15 @@
 //   Tim Coleman (tim@timcoleman.com)
 //   Diego Caravana (diego@toth.it)
 //   Umadevi S (sumadevi@novell.com)
+//   Amit Biswas (amit@amitbiswas.com)
+//   Veerapuram Varadhan (vvaradhan@novell.com)
 //
 // (C) Ximian, Inc. 2002
 // Copyright (C) Tim Coleman, 2002
 //
 
 //
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2008, 2009 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 using Mono.Data.Tds;
 using Mono.Data.Tds.Protocol;
 using System;
+using System.Collections;
 using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
 using System.Data.SqlTypes;
+using System.Globalization;
 using System.Runtime.InteropServices;
 using System.Text;
+using System.Xml;
 
 namespace System.Data.SqlClient {
-       [TypeConverterAttribute (typeof (SqlParameterConverter))]
-#if NET_2_0
+       [TypeConverterAttribute ("System.Data.SqlClient.SqlParameter+SqlParameterConverter, " + Consts.AssemblySystem_Data)]
        public sealed class SqlParameter : DbParameter, IDbDataParameter, IDataParameter, ICloneable
-#else
-       public sealed class SqlParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
-#endif // NET_2_0
        {
                #region Fields
 
                TdsMetaParameter metaParameter;
 
-               SqlParameterCollection container = null;
+               SqlParameterCollection container;
                DbType dbType;
                ParameterDirection direction = ParameterDirection.Input;
-               bool isNullable;
-               bool isVariableSizeType = false;
-               bool isTypeSet = false;
+               bool isTypeSet;
                int offset;
                SqlDbType sqlDbType;
                string sourceColumn;
                DataRowVersion sourceVersion;
+               SqlCompareOptions compareInfo;
+               int localeId;
+               Type sqlType;
+               bool typeChanged;
+               bool sourceColumnNullMapping;
+               string xmlSchemaCollectionDatabase = String.Empty;
+               string xmlSchemaCollectionOwningSchema = String.Empty;
+               string xmlSchemaCollectionName = String.Empty;
+
+               static Hashtable type_mapping;
 
                #endregion // Fields
 
                #region Constructors
 
+               
+               static SqlParameter ()
+               {
+                       if (DbTypeMapping == null)
+                               DbTypeMapping = new Hashtable ();
+                       
+                       DbTypeMapping.Add (SqlDbType.BigInt, typeof (long));
+                       DbTypeMapping.Add (SqlDbType.Bit, typeof (bool));
+                       DbTypeMapping.Add (SqlDbType.Char, typeof (string));
+                       DbTypeMapping.Add (SqlDbType.NChar, typeof (string));
+                       DbTypeMapping.Add (SqlDbType.Text, typeof (string));
+                       DbTypeMapping.Add (SqlDbType.NText, typeof (string));
+                       DbTypeMapping.Add (SqlDbType.VarChar, typeof (string));
+                       DbTypeMapping.Add (SqlDbType.NVarChar, typeof (string));
+                       DbTypeMapping.Add (SqlDbType.SmallDateTime, typeof (DateTime));
+                       DbTypeMapping.Add (SqlDbType.DateTime, typeof (DateTime));
+                       DbTypeMapping.Add (SqlDbType.Decimal, typeof (decimal));
+                       DbTypeMapping.Add (SqlDbType.Float, typeof (double));
+                       DbTypeMapping.Add (SqlDbType.Binary, typeof (byte []));
+                       DbTypeMapping.Add (SqlDbType.Image, typeof (byte []));
+                       DbTypeMapping.Add (SqlDbType.Money, typeof (decimal));
+                       DbTypeMapping.Add (SqlDbType.SmallMoney, typeof (decimal));
+                       DbTypeMapping.Add (SqlDbType.VarBinary, typeof (byte []));
+                       DbTypeMapping.Add (SqlDbType.TinyInt, typeof (byte));
+                       DbTypeMapping.Add (SqlDbType.Int, typeof (int));
+                       DbTypeMapping.Add (SqlDbType.Real, typeof (float));
+                       DbTypeMapping.Add (SqlDbType.SmallInt, typeof (short));
+                       DbTypeMapping.Add (SqlDbType.UniqueIdentifier, typeof (Guid));
+                       DbTypeMapping.Add (SqlDbType.Variant, typeof (object));
+                       DbTypeMapping.Add (SqlDbType.Xml, typeof (string));
+
+                       type_mapping = new Hashtable ();
+
+                       type_mapping.Add (typeof (long), SqlDbType.BigInt);
+                       type_mapping.Add (typeof (SqlTypes.SqlInt64), SqlDbType.BigInt);
+
+                       type_mapping.Add (typeof (bool), SqlDbType.Bit);
+                       type_mapping.Add (typeof (SqlTypes.SqlBoolean), SqlDbType.Bit);
+
+                       type_mapping.Add (typeof (char), SqlDbType.NVarChar);
+                       type_mapping.Add (typeof (char []), SqlDbType.NVarChar);
+                       type_mapping.Add (typeof (SqlTypes.SqlChars), SqlDbType.NVarChar);
+
+                       type_mapping.Add (typeof (string), SqlDbType.NVarChar);
+                       type_mapping.Add (typeof (SqlTypes.SqlString), SqlDbType.NVarChar);
+
+                       type_mapping.Add (typeof (DateTime), SqlDbType.DateTime);
+                       type_mapping.Add (typeof (SqlTypes.SqlDateTime), SqlDbType.DateTime);
+
+                       type_mapping.Add (typeof (decimal), SqlDbType.Decimal);
+                       type_mapping.Add (typeof (SqlTypes.SqlDecimal), SqlDbType.Decimal);
+
+                       type_mapping.Add (typeof (double), SqlDbType.Float);
+                       type_mapping.Add (typeof (SqlTypes.SqlDouble), SqlDbType.Float);
+
+                       type_mapping.Add (typeof (byte []), SqlDbType.VarBinary);
+                       type_mapping.Add (typeof (SqlTypes.SqlBinary), SqlDbType.VarBinary);
+
+                       type_mapping.Add (typeof (SqlTypes.SqlBytes), SqlDbType.VarBinary);
+
+                       type_mapping.Add (typeof (byte), SqlDbType.TinyInt);
+                       type_mapping.Add (typeof (SqlTypes.SqlByte), SqlDbType.TinyInt);
+
+                       type_mapping.Add (typeof (int), SqlDbType.Int);
+                       type_mapping.Add (typeof (SqlTypes.SqlInt32), SqlDbType.Int);
+
+                       type_mapping.Add (typeof (float), SqlDbType.Real);
+                       type_mapping.Add (typeof (SqlTypes.SqlSingle), SqlDbType.Real);
+
+                       type_mapping.Add (typeof (short), SqlDbType.SmallInt);
+                       type_mapping.Add (typeof (SqlTypes.SqlInt16), SqlDbType.SmallInt);
+
+                       type_mapping.Add (typeof (Guid), SqlDbType.UniqueIdentifier);
+                       type_mapping.Add (typeof (SqlTypes.SqlGuid), SqlDbType.UniqueIdentifier);
+
+                       type_mapping.Add (typeof (SqlTypes.SqlMoney), SqlDbType.Money);
+
+                       type_mapping.Add (typeof (XmlReader), SqlDbType.Xml);
+                       type_mapping.Add (typeof (SqlTypes.SqlXml), SqlDbType.Xml);
+
+                       type_mapping.Add (typeof (object), SqlDbType.Variant);
+               }
+               
                public SqlParameter () 
                        : this (String.Empty, SqlDbType.NVarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
                {
                        isTypeSet = false;
                }
 
-               public SqlParameter (string parameterName, object value) 
+               public SqlParameter (string parameterName, object value)
                {
-                       metaParameter = new TdsMetaParameter (parameterName, SqlTypeToFrameworkType (value));
-                       this.sourceVersion = DataRowVersion.Current;
+                       if (parameterName == null)
+                               parameterName = string.Empty;
+                       metaParameter = new TdsMetaParameter (parameterName, GetFrameworkValue);
+                       metaParameter.RawValue = value;
                        InferSqlType (value);
+                       sourceVersion = DataRowVersion.Current;
                }
                
                public SqlParameter (string parameterName, SqlDbType dbType) 
-                       : this (parameterName, dbType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
+                       : this (parameterName, dbType, 0, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, null)
                {
                }
 
                public SqlParameter (string parameterName, SqlDbType dbType, int size) 
-                       : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
+                       : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, null)
                {
                }
                
@@ -100,58 +195,74 @@ namespace System.Data.SqlClient {
                {
                }
                
-               [EditorBrowsable (EditorBrowsableState.Advanced)]        
+               [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) 
                {
+                       if (parameterName == null)
+                               parameterName = string.Empty;
+
                        metaParameter = new TdsMetaParameter (parameterName, size, 
                                                              isNullable, precision, 
-                                                             scale, 
-                                                             SqlTypeToFrameworkType (value));
-                       SqlDbType = dbType;
+                                                             scale,
+                                                             GetFrameworkValue);
+                       metaParameter.RawValue =  value;
+                       if (dbType != SqlDbType.Variant) 
+                               SqlDbType = dbType;
                        Direction = direction;
                        SourceColumn = sourceColumn;
                        SourceVersion = sourceVersion;
                }
 
+               public SqlParameter (string parameterName, SqlDbType dbType, int size, ParameterDirection direction, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, bool sourceColumnNullMapping, Object value, string xmlSchemaCollectionDatabase, string xmlSchemaCollectionOwningSchema, string xmlSchemaCollectionName)
+                       : this (parameterName, dbType, size, direction, false, precision, scale, sourceColumn, sourceVersion, value)
+               {
+                       XmlSchemaCollectionDatabase = xmlSchemaCollectionDatabase;
+                       XmlSchemaCollectionOwningSchema = xmlSchemaCollectionOwningSchema;
+                       XmlSchemaCollectionName = xmlSchemaCollectionName;
+                       SourceColumnNullMapping = sourceColumnNullMapping;
+               }
+
                // This constructor is used internally to construct a
                // SqlParameter.  The value array comes from sp_procedure_params_rowset.
                // This is in SqlCommand.DeriveParameters.
+               //
+               // http://social.msdn.microsoft.com/forums/en-US/transactsql/thread/900756fd-3980-48e3-ae59-a15d7fc15b4c/
                internal SqlParameter (object[] dbValues) 
-                        : this (dbValues [3].ToString (), String.Empty)
+                       : this (dbValues [3].ToString (), (object) null)
                {
-                        Precision = 0;
-                       Scale = 0;
-                       Direction = ParameterDirection.Input;
+                       ParameterName = (string) dbValues [3];
 
-                       ParameterName = (string) dbValues[3];
-
-                       switch ((short) dbValues[5]) {
+                       switch ((short) dbValues [5]) {
                        case 1:
                                Direction = ParameterDirection.Input;
                                break;
                        case 2:
-                               Direction = ParameterDirection.Output;
+                               Direction = ParameterDirection.InputOutput;
                                break;
                        case 3:
-                               Direction = ParameterDirection.InputOutput;
+                               Direction = ParameterDirection.Output;
                                break;
                        case 4:
                                Direction = ParameterDirection.ReturnValue;
                                break;
-                        default:
-                                Direction = ParameterDirection.Input;
-                                break;
+                       default:
+                               Direction = ParameterDirection.Input;
+                               break;
                        }
-                       IsNullable = (dbValues [8] != null && 
-                                      dbValues [8] != DBNull.Value) ? (bool) dbValues [8] : false;
 
-                       if (dbValues [12] != null && dbValues [12] != DBNull.Value)
-                               Precision = (byte) ((short) dbValues [12]);
+                       SqlDbType = (SqlDbType) FrameworkDbTypeFromName ((string) dbValues [16]);
 
-                       if (dbValues [13] != null && dbValues [13] != DBNull.Value)
-                               Scale = (byte) ( (short) dbValues [13]);
+                       if (MetaParameter.IsVariableSizeType) {
+                               if (dbValues [10] != DBNull.Value)
+                                       Size = (int) dbValues [10];
+                       }
 
-                       SetDbTypeName ((string) dbValues [16]);
+                       if (SqlDbType == SqlDbType.Decimal) {
+                               if (dbValues [12] != null && dbValues [12] != DBNull.Value)
+                                       Precision = (byte) ((short) dbValues [12]);
+                               if (dbValues [13] != null && dbValues [13] != DBNull.Value)
+                                       Scale = (byte) ((short) dbValues [13]);
+                       }
                }
 
                #endregion // Constructors
@@ -170,52 +281,32 @@ namespace System.Data.SqlClient {
                        if (!isTypeSet)
                                throw new Exception ("all parameters to have an explicity set type");
 
-                       if (isVariableSizeType) {
+                       if (MetaParameter.IsVariableSizeType) {
                                if (SqlDbType == SqlDbType.Decimal && Precision == 0)
                                        throw new Exception ("Parameter of type 'Decimal' have an explicitly set Precision and Scale");
                                else if (Size == 0)
                                        throw new Exception ("all variable length parameters to have an explicitly set non-zero Size");
                        }
                }
-
-#if ONLY_1_0 || ONLY_1_1       
-               [Browsable (false)]
-               [DataSysDescription ("The parameter generic type.")]
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [RefreshProperties (RefreshProperties.All)]
-#endif                                                  
-               [DataCategory ("Data")]
-               public 
-#if NET_2_0
-               override
-#endif // NET_2_0
-               DbType DbType {
+       
+               public override DbType DbType {
                        get { return dbType; }
-                       set { 
-                               SetDbType (value); 
+                       set {
+                               SetDbType (value);
+                               typeChanged = true;
                                isTypeSet = true;
                        }
                }
 
-               [DataCategory ("Data")]
-#if ONLY_1_0 || ONLY_1_1
-               [DataSysDescription ("Input, output, or bidirectional parameter.")]
-               [DefaultValue (ParameterDirection.Input)]
-#endif
-#if NET_2_0
                [RefreshProperties (RefreshProperties.All)]
-#endif
-               public 
-#if NET_2_0
-               override
-#endif // NET_2_0
-        ParameterDirection Direction {
+               public override
+               ParameterDirection Direction {
                        get { return direction; }
                        set { 
                                direction = value; 
                                switch( direction ) {
                                        case ParameterDirection.Output:
-                                       MetaParameter.Direction = TdsParameterDirection.Output;
+                                               MetaParameter.Direction = TdsParameterDirection.Output;
                                                break;
                                        case ParameterDirection.InputOutput:
                                                MetaParameter.Direction = TdsParameterDirection.InputOutput;
@@ -231,168 +322,139 @@ namespace System.Data.SqlClient {
                        get { return metaParameter; }
                }
 
-#if ONLY_1_0 || ONLY_1_1
-               [Browsable (false)]
-               [DataSysDescription ("a design-time property used for strongly typed code-generation.")]
-               [DefaultValue (false)]
-               [DesignOnly (true)]
-               [EditorBrowsable (EditorBrowsableState.Advanced)]        
-#endif
-               public 
-#if NET_2_0
-               override
-#endif // NET_2_0
-        bool IsNullable        {
+               public override bool IsNullable {
                        get { return metaParameter.IsNullable; }
                        set { metaParameter.IsNullable = value; }
                }
 
                [Browsable (false)]
-               [DataCategory ("Data")]
-#if ONLY_1_0 || ONLY_1_1
-               [DataSysDescription ("Offset in variable length data types.")]
-               [DefaultValue (0)]
-#endif
-#if NET_2_0
                [EditorBrowsable (EditorBrowsableState.Advanced)]
-#endif
                public int Offset {
                        get { return offset; }
                        set { offset = value; }
                }
        
-#if ONLY_1_0 || ONLY_1_1       
-               [DataSysDescription ("Name of the parameter, like '@p1'")]
-               [DefaultValue ("")]
-#endif
-               public 
-#if NET_2_0
-               override
-#endif // NET_2_0
-        string ParameterName {
+               public override string ParameterName {
                        get { return metaParameter.ParameterName; }
-                       set { metaParameter.ParameterName = value; }
+                       set {
+                               if (value == null)
+                                       value = string.Empty;
+                               metaParameter.ParameterName = value;
+                       }
                }
 
-               [DataCategory ("Data")]
-#if ONLY_1_0 || ONLY_1_1
-               [DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
                [DefaultValue (0)]
-#endif
-#if NET_2_0
-               [Browsable (false)]
-               [EditorBrowsable (EditorBrowsableState.Never)]
-#endif         
                public byte Precision {
                        get { return metaParameter.Precision; }
                        set { metaParameter.Precision = value; }
                }
 
-               [DataCategory ("Data")]
-#if ONLY_1_0 || ONLY_1_1
-               [DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
                [DefaultValue (0)]
-#endif
-#if NET_2_0
-               [Browsable (false)]
-                [EditorBrowsable (EditorBrowsableState.Never)]
-#endif
-                public byte Scale {
+               public byte Scale {
                        get { return metaParameter.Scale; }
                        set { metaParameter.Scale = value; }
                }
 
-               [DataCategory ("Data")]
-#if ONLY_1_0 || ONLY_1_1
-               [DataSysDescription ("Size of variable length data types (string & arrays).")]
-               [DefaultValue (0)]
-#endif
-                public 
-#if NET_2_0
-               override
-#endif // NET_2_0
-        int Size {
+               public override int Size {
                        get { return metaParameter.Size; }
                        set { metaParameter.Size = value; }
                }
 
-               [DataCategory ("Data")]
-#if ONLY_1_0 || ONLY_1_1
-               [DataSysDescription ("When used by a DataAdapter.Update, the source column name that is used to find the DataSetColumn name in the ColumnMappings. This is to copy a value between the parameter and a datarow.")]
-               [DefaultValue ("")]
-#endif
-               public 
-#if NET_2_0
-               override
-#endif // NET_2_0
-        string SourceColumn {
-                       get { return sourceColumn; }
+               public override string SourceColumn {
+                       get {
+                               if (sourceColumn == null)
+                                       return string.Empty;
+                               return sourceColumn;
+                       }
                        set { sourceColumn = value; }
                }
 
-               [DataCategory ("Data")]
-#if ONLY_1_0 || ONLY_1_1
-               [DataSysDescription ("When used by a DataAdapter.Update (UpdateCommand only), the version of the DataRow value that is used to update the data source.")]
-               [DefaultValue (DataRowVersion.Current)]
-#endif
-               public 
-#if NET_2_0
-               override
-#endif // NET_2_0
-        DataRowVersion SourceVersion {
+               public override DataRowVersion SourceVersion {
                        get { return sourceVersion; }
                        set { sourceVersion = value; }
                }
                
-               [DataCategory ("Data")]
-#if ONLY_1_0 || ONLY_1_1
-               [DataSysDescription ("The parameter native type.")]
-               [DefaultValue (SqlDbType.NVarChar)]
-#endif
                [RefreshProperties (RefreshProperties.All)]
-#if NET_2_0
                [DbProviderSpecificTypeProperty(true)]
-#endif
                public SqlDbType SqlDbType {
                        get { return sqlDbType; }
-                       set { 
-                               SetSqlDbType (value); 
+                       set {
+                               SetSqlDbType (value);
+                               typeChanged = true;
                                isTypeSet = true;
                        }
                }
 
-               [DataCategory ("Data")]
-#if ONLY_1_0 || ONLY_1_1
-               [DataSysDescription ("Value of the parameter.")]
-               [DefaultValue (null)]
-#endif
-               [TypeConverterAttribute (typeof (StringConverter))]
-#if NET_2_0
-               [RefreshProperties (RefreshProperties.All)]             
-#endif
-               public 
-#if NET_2_0
-               override
-#endif // NET_2_0
-        object Value {
-                       get { return metaParameter.Value; }
-                       set { 
-                               if (!isTypeSet)
+               [TypeConverterAttribute (typeof (StringConverter))]
+               [RefreshProperties (RefreshProperties.All)]
+               public override object Value {
+                       get {
+                               if (sqlType != null)
+                                       return GetSqlValue (metaParameter.RawValue);
+                               return metaParameter.RawValue;
+                       }
+                       set {
+                               if (!isTypeSet) {
                                        InferSqlType (value);
-                               metaParameter.Value = SqlTypeToFrameworkType (value);
+                               }
+
+                               if (value is INullable) {
+                                       sqlType = value.GetType ();
+                                       value = SqlTypeToFrameworkType (value);
+                               }
+                               metaParameter.RawValue = value;
                        }
                }
 
-//#if NET_2_0
-//             public SqlCompareOptions CompareInfo{
+               [Browsable (false)]
+               public SqlCompareOptions CompareInfo{
+                       get{ return compareInfo; }
+                       set{ compareInfo = value; }
+               }
+
+               [Browsable (false)]
+               public int LocaleId { 
+                       get { return localeId; }
+                       set { localeId = value; }
+               }
 
-//#endif
-#if NET_2_0
+               [Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public Object SqlValue {
+                       get {
+                               return GetSqlValue (metaParameter.RawValue);
+                       }
+                       set {
+                               Value = value;
+                       }
+               }
+       
                public override bool SourceColumnNullMapping {
-                       get { return false ; }
-                       set { }
+                       get { return sourceColumnNullMapping; }
+                       set { sourceColumnNullMapping = value; }
+               }
+
+               public string XmlSchemaCollectionDatabase {
+                       get { return xmlSchemaCollectionDatabase; }
+                       set { xmlSchemaCollectionDatabase = (value == null ? String.Empty : value); }
+               }
+
+               public string XmlSchemaCollectionName {
+                       get { return xmlSchemaCollectionName; }
+                       set {
+                               xmlSchemaCollectionName = (value == null ? String.Empty : value);
+                       }
+               }
+
+               public string XmlSchemaCollectionOwningSchema {
+                       get { return xmlSchemaCollectionOwningSchema; } 
+                       set {
+                               xmlSchemaCollectionOwningSchema = (value == null ? String.Empty : value);
+                       }
                }
-#endif
+
+               [BrowsableAttribute(false)]
+               public string UdtTypeName { get; set; }
 
                #endregion // Properties
 
@@ -405,74 +467,92 @@ namespace System.Data.SqlClient {
 
                // If the value is set without the DbType/SqlDbType being set, then we
                // infer type information.
-               private void InferSqlType (object value)
+               void InferSqlType (object value)
                {
-                       if (value == null || value == DBNull.Value)
+                       if (value == null || value == DBNull.Value) {
+                               SetSqlDbType (SqlDbType.NVarChar);
                                return;
+                       }
 
                        Type type = value.GetType ();
+                       if (type.IsEnum)
+                               type = Enum.GetUnderlyingType (type);
+                       object t = type_mapping [type];
+                       if (t == null)
+                               throw new ArgumentException (String.Format ("The parameter data type of {0} is invalid.", type.FullName));
+                       SetSqlDbType ((SqlDbType) t);
+               }
+
+               // Returns System.Type corresponding to the underlying SqlDbType
+               internal override Type SystemType {
+                       get {
+                               return (Type) DbTypeMapping [sqlDbType];
+                       }
+               }
 
-                       string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
+               internal override object FrameworkDbType {
+                       get {
+                               return sqlDbType;
+                       }
+                       
+                       set {
+                               object t;
+                               try {
+                                       t = (DbType) DbTypeFromName ((string)value);
+                                       SetDbType ((DbType)t);
+                               } catch (ArgumentException) {
+                                       t = (SqlDbType)FrameworkDbTypeFromName ((string)value);
+                                       SetSqlDbType ((SqlDbType) t);
+                               }
+                       }
+               }
 
-                       switch (type.FullName) {
-                       case "System.Int64":
-                       case "System.Data.SqlTypes.SqlInt64":
-                               SetSqlDbType (SqlDbType.BigInt);
-                               break;
-                       case "System.Boolean":
-                       case "System.Data.SqlTypes.SqlBoolean":
-                               SetSqlDbType (SqlDbType.Bit);
-                               break;
-                       case "System.String":
-                       case "System.Data.SqlTypes.SqlString":
-                               SetSqlDbType (SqlDbType.NVarChar);
-                               break;
-                       case "System.DateTime":
-                       case "System.Data.SqlTypes.SqlDateTime":
-                               SetSqlDbType (SqlDbType.DateTime);
-                               break;
-                       case "System.Decimal":
-                       case "System.Data.SqlTypes.SqlDecimal":
-                               SetSqlDbType (SqlDbType.Decimal);
-                               break;
-                       case "System.Double":
-                       case "System.Data.SqlTypes.SqlDouble":
-                               SetSqlDbType (SqlDbType.Float);
-                               break;
-                       case "System.Byte[]":
-                       case "System.Data.SqlTypes.SqlBinary":
-                               SetSqlDbType (SqlDbType.VarBinary);
-                               break;
-                       case "System.Byte":
-                       case "System.Data.SqlTypes.SqlByte":
-                               SetSqlDbType (SqlDbType.TinyInt);
-                               break;
-                       case "System.Int32":
-                       case "System.Data.SqlTypes.SqlInt32":
-                               SetSqlDbType (SqlDbType.Int);
-                               break;
-                       case "System.Single":
-                       case "System.Data.SqlTypes.Single":
-                               SetSqlDbType (SqlDbType.Real);
-                               break;
-                       case "System.Int16":
-                       case "System.Data.SqlTypes.SqlInt16":
-                               SetSqlDbType (SqlDbType.SmallInt);
-                               break;
-                       case "System.Guid":
-                       case "System.Data.SqlTypes.SqlGuid":
-                               SetSqlDbType (SqlDbType.UniqueIdentifier);
-                               break;
-                       case "System.Money":
-                       case "System.SmallMoney":
-                       case "System.Data.SqlTypes.SqlMoney":
-                               SetSqlDbType (SqlDbType.Money);
-                               break;
-                       case "System.Object":
-                               SetSqlDbType (SqlDbType.Variant); 
-                               break;
-                       default:
-                               throw new ArgumentException (exception);                                
+               DbType DbTypeFromName (string name)
+               {
+                       switch (name.ToLower ()) {
+                               case "ansistring":
+                                       return DbType.AnsiString;
+                               case "ansistringfixedlength":
+                                       return DbType.AnsiStringFixedLength;
+                               case "binary": 
+                                       return DbType.Binary;
+                               case "boolean":
+                                       return DbType.Boolean;
+                               case "byte":
+                                       return DbType.Byte;
+                               case "currency": 
+                                       return DbType.Currency;
+                               case "date":
+                                       return DbType.Date;
+                               case "datetime": 
+                                       return DbType.DateTime;
+                               case "decimal":
+                                       return DbType.Decimal;
+                               case "double": 
+                                       return DbType.Double;
+                               case "guid": 
+                                       return DbType.Guid;
+                               case "int16": 
+                                       return DbType.Int16;
+                               case "int32": 
+                                       return DbType.Int32;
+                               case "int64": 
+                                       return DbType.Int64;
+                               case "object": 
+                                       return DbType.Object;
+                               case "single": 
+                                       return DbType.Single;
+                               case "string": 
+                                       return DbType.String;
+                               case "stringfixedlength": 
+                                       return DbType.StringFixedLength;
+                               case "time": 
+                                       return DbType.Time;
+                               case "xml": 
+                                       return DbType.Xml;
+                               default:
+                                       string exception = String.Format ("No mapping exists from {0} to a known DbType.", name);
+                                       throw new ArgumentException (exception);
                        }
                }
 
@@ -481,23 +561,21 @@ namespace System.Data.SqlClient {
                // to an SqlDbType, throw an exception.
                private void SetDbType (DbType type)
                {
-                       string exception = String.Format ("No mapping exists from DbType {0} to a known SqlDbType.", type);
-
                        switch (type) {
                        case DbType.AnsiString:
                                MetaParameter.TypeName = "varchar";
                                sqlDbType = SqlDbType.VarChar;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case DbType.AnsiStringFixedLength:
                                MetaParameter.TypeName = "char";
                                sqlDbType = SqlDbType.Char;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case DbType.Binary:
                                MetaParameter.TypeName = "varbinary";
                                sqlDbType = SqlDbType.VarBinary;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case DbType.Boolean:
                                MetaParameter.TypeName = "bit";
@@ -516,6 +594,10 @@ namespace System.Data.SqlClient {
                                MetaParameter.TypeName = "datetime";
                                sqlDbType = SqlDbType.DateTime;
                                break;
+                       case DbType.DateTime2:
+                               MetaParameter.TypeName = "datetime2";
+                               sqlDbType = SqlDbType.DateTime2;
+                               break;
                        case DbType.Decimal:
                                MetaParameter.TypeName = "decimal";
                                sqlDbType = SqlDbType.Decimal;
@@ -551,109 +633,94 @@ namespace System.Data.SqlClient {
                        case DbType.String:
                                MetaParameter.TypeName = "nvarchar";
                                sqlDbType = SqlDbType.NVarChar;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case DbType.StringFixedLength:
                                MetaParameter.TypeName = "nchar";
                                sqlDbType = SqlDbType.NChar;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case DbType.Time:
                                MetaParameter.TypeName = "datetime";
                                sqlDbType = SqlDbType.DateTime;
                                break;
+                               // Handle Xml type as string
+                       case DbType.Xml:
+                               MetaParameter.TypeName = "xml";
+                               sqlDbType = SqlDbType.Xml;
+                               MetaParameter.IsVariableSizeType = true;
+                               break;
                        default:
+                               string exception = String.Format ("No mapping exists from DbType {0} to a known SqlDbType.", type);
                                throw new ArgumentException (exception);
                        }
                        dbType = type;
                }
 
                // Used by internal constructor which has a SQL Server typename
-               private void SetDbTypeName (string dbTypeName)
+               private SqlDbType FrameworkDbTypeFromName (string dbTypeName)
                {
                        switch (dbTypeName.ToLower ()) {        
                        case "bigint":
-                               SqlDbType = SqlDbType.BigInt;
-                               break;
+                               return SqlDbType.BigInt;
                        case "binary":
-                               SqlDbType = SqlDbType.Binary;
-                               break;
+                               return SqlDbType.Binary;
                        case "bit":
-                               SqlDbType = SqlDbType.Bit;
-                               break;
+                               return SqlDbType.Bit;
                        case "char":
-                               SqlDbType = SqlDbType.Char;
-                               break;
+                               return SqlDbType.Char;
                        case "datetime":
-                               SqlDbType = SqlDbType.DateTime;
-                               break;
+                               return SqlDbType.DateTime;
                        case "decimal":
-                               SqlDbType = SqlDbType.Decimal;
-                               break;
+                               return SqlDbType.Decimal;
                        case "float":
-                               SqlDbType = SqlDbType.Float;
-                               break;
+                               return SqlDbType.Float;
                        case "image":
-                               SqlDbType = SqlDbType.Image;
-                               break;
+                               return SqlDbType.Image;
                        case "int":
-                               SqlDbType = SqlDbType.Int;
-                               break;
+                               return SqlDbType.Int;
                        case "money":
-                               SqlDbType = SqlDbType.Money;
-                               break;
+                               return SqlDbType.Money;
                        case "nchar":
-                               SqlDbType = SqlDbType.NChar;
-                               break;
+                               return SqlDbType.NChar;
                        case "ntext":
-                               SqlDbType = SqlDbType.NText;
-                               break;
+                               return SqlDbType.NText;
                        case "nvarchar":
-                               SqlDbType = SqlDbType.NVarChar;
-                               break;
+                               return SqlDbType.NVarChar;
                        case "real":
-                               SqlDbType = SqlDbType.Real;
-                               break;
+                               return SqlDbType.Real;
                        case "smalldatetime":
-                               SqlDbType = SqlDbType.SmallDateTime;
-                               break;
+                               return SqlDbType.SmallDateTime;
                        case "smallint":
-                               SqlDbType = SqlDbType.SmallInt;
-                               break;
+                               return SqlDbType.SmallInt;
                        case "smallmoney":
-                               SqlDbType = SqlDbType.SmallMoney;
-                               break;
+                               return SqlDbType.SmallMoney;
                        case "text":
-                               SqlDbType = SqlDbType.Text;
-                               break;
+                               return SqlDbType.Text;
                        case "timestamp":
-                               SqlDbType = SqlDbType.Timestamp;
-                               break;
+                               return SqlDbType.Timestamp;
                        case "tinyint":
-                               SqlDbType = SqlDbType.TinyInt;
-                               break;
+                               return SqlDbType.TinyInt;
                        case "uniqueidentifier":
-                               SqlDbType = SqlDbType.UniqueIdentifier;
-                               break;
+                               return SqlDbType.UniqueIdentifier;
                        case "varbinary":
-                               SqlDbType = SqlDbType.VarBinary;
-                               break;
+                               return SqlDbType.VarBinary;
                        case "varchar":
-                               SqlDbType = SqlDbType.VarChar;
-                               break;
+                               return SqlDbType.VarChar;
+                       case "sql_variant":
+                               return SqlDbType.Variant;
+                       case "xml":
+                               return SqlDbType.Xml;
                        default:
-                               SqlDbType = SqlDbType.Variant;
-                               break;
+                               return SqlDbType.Variant;
                        }
                }
 
                // When the SqlDbType is set, we also set the DbType, as well as the SQL Server
                // string representation of the type name.  If the SqlDbType is not convertible
                // to a DbType, throw an exception.
-               private void SetSqlDbType (SqlDbType type)
+               internal void SetSqlDbType (SqlDbType type)
                {
-                       string exception = String.Format ("No mapping exists from SqlDbType {0} to a known DbType.", type);
-
                        switch (type) {
                        case SqlDbType.BigInt:
                                MetaParameter.TypeName = "bigint";
@@ -662,7 +729,7 @@ namespace System.Data.SqlClient {
                        case SqlDbType.Binary:
                                MetaParameter.TypeName = "binary";
                                dbType = DbType.Binary;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case SqlDbType.Timestamp:
                                MetaParameter.TypeName = "timestamp";
@@ -671,7 +738,7 @@ namespace System.Data.SqlClient {
                        case SqlDbType.VarBinary:
                                MetaParameter.TypeName = "varbinary";
                                dbType = DbType.Binary;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case SqlDbType.Bit:
                                MetaParameter.TypeName = "bit";
@@ -680,7 +747,7 @@ namespace System.Data.SqlClient {
                        case SqlDbType.Char:
                                MetaParameter.TypeName = "char";
                                dbType = DbType.AnsiStringFixedLength;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case SqlDbType.DateTime:
                                MetaParameter.TypeName = "datetime";
@@ -701,7 +768,7 @@ namespace System.Data.SqlClient {
                        case SqlDbType.Image:
                                MetaParameter.TypeName = "image";
                                dbType = DbType.Binary;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case SqlDbType.Int:
                                MetaParameter.TypeName = "int";
@@ -718,17 +785,17 @@ namespace System.Data.SqlClient {
                        case SqlDbType.NChar:
                                MetaParameter.TypeName = "nchar";
                                dbType = DbType.StringFixedLength;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case SqlDbType.NText:
                                MetaParameter.TypeName = "ntext";
                                dbType = DbType.String;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case SqlDbType.NVarChar:
                                MetaParameter.TypeName = "nvarchar";
                                dbType = DbType.String;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case SqlDbType.Real:
                                MetaParameter.TypeName = "real";
@@ -741,12 +808,12 @@ namespace System.Data.SqlClient {
                        case SqlDbType.Text:
                                MetaParameter.TypeName = "text";
                                dbType = DbType.AnsiString;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case SqlDbType.VarChar:
                                MetaParameter.TypeName = "varchar";
                                dbType = DbType.AnsiString;
-                               isVariableSizeType = true;
+                               MetaParameter.IsVariableSizeType = true;
                                break;
                        case SqlDbType.TinyInt:
                                MetaParameter.TypeName = "tinyint";
@@ -760,8 +827,14 @@ namespace System.Data.SqlClient {
                                MetaParameter.TypeName = "sql_variant";
                                dbType = DbType.Object;
                                break;
+                       case SqlDbType.Xml:
+                               MetaParameter.TypeName = "xml";
+                               dbType = DbType.Xml;
+                               MetaParameter.IsVariableSizeType = true;
+                               break;
                        default:
-                               throw new ArgumentException (exception);
+                               string exception = String.Format ("No mapping exists from SqlDbType {0} to a known DbType.", type);
+                               throw new ArgumentOutOfRangeException ("SqlDbType", exception);
                        }
                        sqlDbType = type;
                }
@@ -771,50 +844,231 @@ namespace System.Data.SqlClient {
                        return ParameterName;
                }
 
-               private object SqlTypeToFrameworkType (object value)
+               object GetFrameworkValue (object rawValue, ref bool updated)
                {
-                       if (! (value is INullable)) // if the value is not SqlType
+                       object tdsValue;
+
+                       updated = typeChanged || updated;
+                       if (updated) {
+                               tdsValue = SqlTypeToFrameworkType (rawValue);
+                               typeChanged = false;
+                       } else
+                               tdsValue = null;
+                       return tdsValue;
+               }
+               
+               // TODO: Code copied from SqlDataReader, need a better approach
+               object GetSqlValue (object value)
+               {               
+                       if (value == null)
                                return value;
+                       switch (sqlDbType) {
+                       case SqlDbType.BigInt:
+                               if (value == DBNull.Value)
+                                       return SqlInt64.Null;
+                               return (SqlInt64) ((long) value);
+                       case SqlDbType.Binary:
+                       case SqlDbType.Image:
+                       case SqlDbType.VarBinary:
+                       case SqlDbType.Timestamp:
+                               if (value == DBNull.Value)
+                                       return SqlBinary.Null;
+                               return (SqlBinary) (byte[]) value;
+                       case SqlDbType.Bit:
+                               if (value == DBNull.Value)
+                                       return SqlBoolean.Null;
+                               return (SqlBoolean) ((bool) value);
+                       case SqlDbType.Char:
+                       case SqlDbType.NChar:
+                       case SqlDbType.NText:
+                       case SqlDbType.NVarChar:
+                       case SqlDbType.Text:
+                       case SqlDbType.VarChar:
+                               if (value == DBNull.Value)
+                                       return SqlString.Null;
+
+                               string str;
+                               Type type = value.GetType ();
+                               if (type == typeof (char))
+                                       str = value.ToString ();
+                               else if (type == typeof (char[]))
+                                       str = new String ((char[])value);
+                               else
+                                       str = ((string)value);
+                                       return (SqlString) str;
+                       case SqlDbType.DateTime:
+                       case SqlDbType.SmallDateTime:
+                               if (value == DBNull.Value)
+                                       return SqlDateTime.Null;
+                               return (SqlDateTime) ((DateTime) value);
+                       case SqlDbType.Decimal:
+                               if (value == DBNull.Value)
+                                       return SqlDecimal.Null;
+                               if (value is TdsBigDecimal)
+                                       return SqlDecimal.FromTdsBigDecimal ((TdsBigDecimal) value);
+                               return (SqlDecimal) ((decimal) value);
+                       case SqlDbType.Float:
+                               if (value == DBNull.Value)
+                                       return SqlDouble.Null;
+                               return (SqlDouble) ((double) value);
+                       case SqlDbType.Int:
+                               if (value == DBNull.Value)
+                                       return SqlInt32.Null;
+                               return (SqlInt32) ((int) value);
+                       case SqlDbType.Money:
+                       case SqlDbType.SmallMoney:
+                               if (value == DBNull.Value)
+                                       return SqlMoney.Null;
+                               return (SqlMoney) ((decimal) value);
+                       case SqlDbType.Real:
+                               if (value == DBNull.Value)
+                                       return SqlSingle.Null;
+                               return (SqlSingle) ((float) value);
+                       case SqlDbType.UniqueIdentifier:
+                               if (value == DBNull.Value)
+                                       return SqlGuid.Null;
+                               return (SqlGuid) ((Guid) value);
+                       case SqlDbType.SmallInt:
+                               if (value == DBNull.Value)
+                                       return SqlInt16.Null;
+                               return (SqlInt16) ((short) value);
+                       case SqlDbType.TinyInt:
+                               if (value == DBNull.Value)
+                                       return SqlByte.Null;
+                               return (SqlByte) ((byte) value);
+                       case SqlDbType.Xml:
+                               if (value == DBNull.Value)
+                                       return SqlXml.Null;
+                               return (SqlXml) value;
+                       default:
+                               throw new NotImplementedException ("Type '" + sqlDbType + "' not implemented.");
+                       }
+               }
+               
+               object SqlTypeToFrameworkType (object value)
+               {
+                       INullable nullable = value as INullable;
+                       if (nullable == null)
+                               return ConvertToFrameworkType (value);
 
+                       if (nullable.IsNull)
+                               return DBNull.Value;
+
+                       Type type = value.GetType ();
                        // Map to .net type, as Mono TDS respects only types from .net
-                       switch (value.GetType ().FullName) {
-                       case "System.Data.SqlTypes.SqlBinary":
-                               return ( (SqlBinary) value).Value;
-                       case "System.Data.SqlTypes.SqlBoolean":
-                               return ( (SqlBoolean) value).Value;
-                       case "System.Data.SqlTypes.SqlByte":
-                               return ( (SqlByte) value).Value;
-                       case "System.Data.SqlTypes.SqlDateTime":
-                               return ( (SqlDateTime) value).Value;
-                       case "System.Data.SqlTypes.SqlDecimal":
-                               return ( (SqlDecimal) value).Value;
-                       case "System.Data.SqlTypes.SqlDouble":
-                               return ( (SqlDouble) value).Value;
-                       case "System.Data.SqlTypes.SqlGuid":
-                               return ( (SqlGuid) value).Value;
-                       case "System.Data.SqlTypes.SqlInt16":
-                               return ( (SqlInt16) value).Value;
-                       case "System.Data.SqlTypes.SqlInt32 ":
-                               return ( (SqlInt32 ) value).Value;
-                       case "System.Data.SqlTypes.SqlInt64":
-                               return ( (SqlInt64) value).Value;
-                       case "System.Data.SqlTypes.SqlMoney":
-                               return ( (SqlMoney) value).Value;
-                       case "System.Data.SqlTypes.SqlSingle":
-                               return ( (SqlSingle) value).Value;
-                       case "System.Data.SqlTypes.SqlString":
-                               return ( (SqlString) value).Value;
+
+                       if (typeof (SqlString) == type) {
+                               return ((SqlString) value).Value;
+                       }
+
+                       if (typeof (SqlInt16) == type) {
+                               return ((SqlInt16) value).Value;
+                       }
+
+                       if (typeof (SqlInt32) == type) {
+                               return ((SqlInt32) value).Value;
+                       }
+
+                       if (typeof (SqlDateTime) == type) {
+                               return ((SqlDateTime) value).Value;
+                       }
+
+                       if (typeof (SqlInt64) == type) {
+                               return ((SqlInt64) value).Value;
+                       }
+
+                       if (typeof (SqlBinary) == type) {
+                               return ((SqlBinary) value).Value;
+                       }
+                       
+                       if (typeof (SqlBytes) == type) {
+                               return ((SqlBytes) value).Value;
+                       }
+
+                       if (typeof (SqlChars) == type) {
+                               return ((SqlChars) value).Value;
+                       }
+
+                       if (typeof (SqlBoolean) == type) {
+                               return ((SqlBoolean) value).Value;
+                       }
+
+                       if (typeof (SqlByte) == type) {
+                               return ((SqlByte) value).Value;
+                       }
+
+                       if (typeof (SqlDecimal) == type) {
+                               return ((SqlDecimal) value).Value;
+                       }
+
+                       if (typeof (SqlDouble) == type) {
+                               return ((SqlDouble) value).Value;
+                       }
+
+                       if (typeof (SqlGuid) == type) {
+                               return ((SqlGuid) value).Value;
+                       }
+
+                       if (typeof (SqlMoney) == type) {
+                               return ((SqlMoney) value).Value;
                        }
+
+                       if (typeof (SqlSingle) == type) {
+                               return ((SqlSingle) value).Value;
+                       }
+
                        return value;
                }
 
-#if NET_2_0
-                [MonoTODO]
-                public override void ResetDbType ()
-                {
-                        throw new NotImplementedException ();
-                }
-#endif // NET_2_0
+               internal object ConvertToFrameworkType (object value)
+               {
+                       if (value == null || value == DBNull.Value)
+                               return value;
+                       if (sqlDbType == SqlDbType.Variant)
+                               return metaParameter.Value;
+
+                       Type frameworkType = SystemType;
+                       if (frameworkType == null)
+                               throw new NotImplementedException ("Type Not Supported : " + sqlDbType.ToString());
+
+                       Type valueType = value.GetType ();
+                       if (valueType == frameworkType)
+                               return value;
+
+                       object sqlvalue = null;
+
+                       try {
+                               sqlvalue = ConvertToFrameworkType (value, frameworkType);
+                       } catch (FormatException ex) {
+                               throw new FormatException (string.Format (CultureInfo.InvariantCulture,
+                                       "Parameter value could not be converted from {0} to {1}.",
+                                       valueType.Name, frameworkType.Name), ex);
+                       }
+
+                       return sqlvalue;
+               }
+
+               object ConvertToFrameworkType (object value, Type frameworkType)
+               {
+                       object sqlvalue = Convert.ChangeType (value, frameworkType);
+                       switch (sqlDbType) {
+                       case SqlDbType.Money:
+                       case SqlDbType.SmallMoney:
+                               sqlvalue = Decimal.Round ((decimal) sqlvalue, 4);
+                               break;
+                       }
+                       return sqlvalue;
+               }
+
+               public override void ResetDbType ()
+               {
+                       InferSqlType (Value);
+               }
+
+               public void ResetSqlDbType ()
+               {
+                       InferSqlType (Value);
+               }
 
                #endregion // Methods
        }