Merge pull request #1773 from ztzg/sql-server-datetime2
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlParameter.cs
1 //
2 // System.Data.SqlClient.SqlParameter.cs
3 //
4 // Author:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Daniel Morgan (danmorg@sc.rr.com)
7 //   Tim Coleman (tim@timcoleman.com)
8 //   Diego Caravana (diego@toth.it)
9 //   Umadevi S (sumadevi@novell.com)
10 //   Amit Biswas (amit@amitbiswas.com)
11 //   Veerapuram Varadhan (vvaradhan@novell.com)
12 //
13 // (C) Ximian, Inc. 2002
14 // Copyright (C) Tim Coleman, 2002
15 //
16
17 //
18 // Copyright (C) 2004, 2008, 2009 Novell, Inc (http://www.novell.com)
19 //
20 // Permission is hereby granted, free of charge, to any person obtaining
21 // a copy of this software and associated documentation files (the
22 // "Software"), to deal in the Software without restriction, including
23 // without limitation the rights to use, copy, modify, merge, publish,
24 // distribute, sublicense, and/or sell copies of the Software, and to
25 // permit persons to whom the Software is furnished to do so, subject to
26 // the following conditions:
27 // 
28 // The above copyright notice and this permission notice shall be
29 // included in all copies or substantial portions of the Software.
30 // 
31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 //
39
40 using Mono.Data.Tds;
41 using Mono.Data.Tds.Protocol;
42 using System;
43 using System.Collections;
44 using System.ComponentModel;
45 using System.Data;
46 using System.Data.Common;
47 using System.Data.SqlTypes;
48 using System.Globalization;
49 using System.Runtime.InteropServices;
50 using System.Text;
51 using System.Xml;
52
53 namespace System.Data.SqlClient {
54         [TypeConverterAttribute ("System.Data.SqlClient.SqlParameter+SqlParameterConverter, " + Consts.AssemblySystem_Data)]
55         public sealed class SqlParameter : DbParameter, IDbDataParameter, IDataParameter, ICloneable
56         {
57 #region Import from old DbParameter
58                 static Hashtable dbTypeMapping = new Hashtable ();
59                 internal static Hashtable DbTypeMapping {
60                         get { return dbTypeMapping;}
61                         set { dbTypeMapping = value;}
62                 }
63
64                 // LAMESPEC: Implementors should populate the dbTypeMapping accordingly
65                 internal Type SystemType {
66                         get {
67                                 return (Type) dbTypeMapping [SqlDbType];
68                         }
69                 }
70 #endregion
71
72                 #region Fields
73
74                 TdsMetaParameter metaParameter;
75
76                 SqlParameterCollection container;
77                 DbType dbType;
78                 ParameterDirection direction = ParameterDirection.Input;
79                 bool isTypeSet;
80                 int offset;
81                 SqlDbType sqlDbType;
82                 string sourceColumn;
83                 DataRowVersion sourceVersion;
84                 SqlCompareOptions compareInfo;
85                 int localeId;
86                 Type sqlType;
87                 bool typeChanged;
88                 bool sourceColumnNullMapping;
89                 string xmlSchemaCollectionDatabase = String.Empty;
90                 string xmlSchemaCollectionOwningSchema = String.Empty;
91                 string xmlSchemaCollectionName = String.Empty;
92
93                 static Hashtable type_mapping;
94
95                 #endregion // Fields
96
97                 #region Constructors
98
99                 
100                 static SqlParameter ()
101                 {
102                         if (DbTypeMapping == null)
103                                 DbTypeMapping = new Hashtable ();
104                         
105                         DbTypeMapping.Add (SqlDbType.BigInt, typeof (long));
106                         DbTypeMapping.Add (SqlDbType.Bit, typeof (bool));
107                         DbTypeMapping.Add (SqlDbType.Char, typeof (string));
108                         DbTypeMapping.Add (SqlDbType.NChar, typeof (string));
109                         DbTypeMapping.Add (SqlDbType.Text, typeof (string));
110                         DbTypeMapping.Add (SqlDbType.NText, typeof (string));
111                         DbTypeMapping.Add (SqlDbType.VarChar, typeof (string));
112                         DbTypeMapping.Add (SqlDbType.NVarChar, typeof (string));
113                         DbTypeMapping.Add (SqlDbType.SmallDateTime, typeof (DateTime));
114                         DbTypeMapping.Add (SqlDbType.DateTime, typeof (DateTime));
115                         DbTypeMapping.Add (SqlDbType.DateTime2, typeof (DateTime));
116                         DbTypeMapping.Add (SqlDbType.DateTimeOffset, typeof (DateTimeOffset));
117                         DbTypeMapping.Add (SqlDbType.Decimal, typeof (decimal));
118                         DbTypeMapping.Add (SqlDbType.Float, typeof (double));
119                         DbTypeMapping.Add (SqlDbType.Binary, typeof (byte []));
120                         DbTypeMapping.Add (SqlDbType.Image, typeof (byte []));
121                         DbTypeMapping.Add (SqlDbType.Money, typeof (decimal));
122                         DbTypeMapping.Add (SqlDbType.SmallMoney, typeof (decimal));
123                         DbTypeMapping.Add (SqlDbType.VarBinary, typeof (byte []));
124                         DbTypeMapping.Add (SqlDbType.TinyInt, typeof (byte));
125                         DbTypeMapping.Add (SqlDbType.Int, typeof (int));
126                         DbTypeMapping.Add (SqlDbType.Real, typeof (float));
127                         DbTypeMapping.Add (SqlDbType.SmallInt, typeof (short));
128                         DbTypeMapping.Add (SqlDbType.UniqueIdentifier, typeof (Guid));
129                         DbTypeMapping.Add (SqlDbType.Variant, typeof (object));
130                         DbTypeMapping.Add (SqlDbType.Xml, typeof (string));
131
132                         type_mapping = new Hashtable ();
133
134                         type_mapping.Add (typeof (long), SqlDbType.BigInt);
135                         type_mapping.Add (typeof (SqlTypes.SqlInt64), SqlDbType.BigInt);
136
137                         type_mapping.Add (typeof (bool), SqlDbType.Bit);
138                         type_mapping.Add (typeof (SqlTypes.SqlBoolean), SqlDbType.Bit);
139
140                         type_mapping.Add (typeof (char), SqlDbType.NVarChar);
141                         type_mapping.Add (typeof (char []), SqlDbType.NVarChar);
142                         type_mapping.Add (typeof (SqlTypes.SqlChars), SqlDbType.NVarChar);
143
144                         type_mapping.Add (typeof (string), SqlDbType.NVarChar);
145                         type_mapping.Add (typeof (SqlTypes.SqlString), SqlDbType.NVarChar);
146
147                         type_mapping.Add (typeof (DateTime), SqlDbType.DateTime);
148                         type_mapping.Add (typeof (SqlTypes.SqlDateTime), SqlDbType.DateTime);
149
150                         type_mapping.Add (typeof (decimal), SqlDbType.Decimal);
151                         type_mapping.Add (typeof (SqlTypes.SqlDecimal), SqlDbType.Decimal);
152
153                         type_mapping.Add (typeof (double), SqlDbType.Float);
154                         type_mapping.Add (typeof (SqlTypes.SqlDouble), SqlDbType.Float);
155
156                         type_mapping.Add (typeof (byte []), SqlDbType.VarBinary);
157                         type_mapping.Add (typeof (SqlTypes.SqlBinary), SqlDbType.VarBinary);
158
159                         type_mapping.Add (typeof (SqlTypes.SqlBytes), SqlDbType.VarBinary);
160
161                         type_mapping.Add (typeof (byte), SqlDbType.TinyInt);
162                         type_mapping.Add (typeof (SqlTypes.SqlByte), SqlDbType.TinyInt);
163
164                         type_mapping.Add (typeof (int), SqlDbType.Int);
165                         type_mapping.Add (typeof (SqlTypes.SqlInt32), SqlDbType.Int);
166
167                         type_mapping.Add (typeof (float), SqlDbType.Real);
168                         type_mapping.Add (typeof (SqlTypes.SqlSingle), SqlDbType.Real);
169
170                         type_mapping.Add (typeof (short), SqlDbType.SmallInt);
171                         type_mapping.Add (typeof (SqlTypes.SqlInt16), SqlDbType.SmallInt);
172
173                         type_mapping.Add (typeof (Guid), SqlDbType.UniqueIdentifier);
174                         type_mapping.Add (typeof (SqlTypes.SqlGuid), SqlDbType.UniqueIdentifier);
175
176                         type_mapping.Add (typeof (SqlTypes.SqlMoney), SqlDbType.Money);
177
178                         type_mapping.Add (typeof (XmlReader), SqlDbType.Xml);
179                         type_mapping.Add (typeof (SqlTypes.SqlXml), SqlDbType.Xml);
180
181                         type_mapping.Add (typeof (object), SqlDbType.Variant);
182                         type_mapping.Add (typeof (DateTimeOffset), SqlDbType.DateTimeOffset);
183                 }
184                 
185                 public SqlParameter () 
186                         : this (String.Empty, SqlDbType.NVarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
187                 {
188                         isTypeSet = false;
189                 }
190
191                 public SqlParameter (string parameterName, object value)
192                 {
193                         if (parameterName == null)
194                                 parameterName = string.Empty;
195                         metaParameter = new TdsMetaParameter (parameterName, GetFrameworkValue);
196                         metaParameter.RawValue = value;
197                         InferSqlType (value);
198                         sourceVersion = DataRowVersion.Current;
199                 }
200                 
201                 public SqlParameter (string parameterName, SqlDbType dbType) 
202                         : this (parameterName, dbType, 0, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, null)
203                 {
204                 }
205
206                 public SqlParameter (string parameterName, SqlDbType dbType, int size) 
207                         : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, null)
208                 {
209                 }
210                 
211                 public SqlParameter (string parameterName, SqlDbType dbType, int size, string sourceColumn) 
212                         : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, sourceColumn, DataRowVersion.Current, null)
213                 {
214                 }
215                 
216                 [EditorBrowsable (EditorBrowsableState.Advanced)]
217                 public SqlParameter (string parameterName, SqlDbType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value) 
218                 {
219                         if (parameterName == null)
220                                 parameterName = string.Empty;
221
222                         metaParameter = new TdsMetaParameter (parameterName, size, 
223                                                               isNullable, precision, 
224                                                               scale,
225                                                               GetFrameworkValue);
226                         metaParameter.RawValue =  value;
227                         SqlDbType = dbType;
228                         Direction = direction;
229                         SourceColumn = sourceColumn;
230                         SourceVersion = sourceVersion;
231                 }
232
233                 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)
234                         : this (parameterName, dbType, size, direction, false, precision, scale, sourceColumn, sourceVersion, value)
235                 {
236                         XmlSchemaCollectionDatabase = xmlSchemaCollectionDatabase;
237                         XmlSchemaCollectionOwningSchema = xmlSchemaCollectionOwningSchema;
238                         XmlSchemaCollectionName = xmlSchemaCollectionName;
239                         SourceColumnNullMapping = sourceColumnNullMapping;
240                 }
241
242                 // This constructor is used internally to construct a
243                 // SqlParameter.  The value array comes from sp_procedure_params_rowset.
244                 // This is in SqlCommand.DeriveParameters.
245                 //
246                 // http://social.msdn.microsoft.com/forums/en-US/transactsql/thread/900756fd-3980-48e3-ae59-a15d7fc15b4c/
247                 internal SqlParameter (object[] dbValues) 
248                         : this (dbValues [3].ToString (), (object) null)
249                 {
250                         ParameterName = (string) dbValues [3];
251
252                         switch ((short) dbValues [5]) {
253                         case 1:
254                                 Direction = ParameterDirection.Input;
255                                 break;
256                         case 2:
257                                 Direction = ParameterDirection.InputOutput;
258                                 break;
259                         case 3:
260                                 Direction = ParameterDirection.Output;
261                                 break;
262                         case 4:
263                                 Direction = ParameterDirection.ReturnValue;
264                                 break;
265                         default:
266                                 Direction = ParameterDirection.Input;
267                                 break;
268                         }
269
270                         SqlDbType = (SqlDbType) FrameworkDbTypeFromName ((string) dbValues [16]);
271
272                         if (MetaParameter.IsVariableSizeType) {
273                                 if (dbValues [10] != DBNull.Value)
274                                         Size = (int) dbValues [10];
275                         }
276
277                         if (SqlDbType == SqlDbType.Decimal) {
278                                 if (dbValues [12] != null && dbValues [12] != DBNull.Value)
279                                         Precision = (byte) ((short) dbValues [12]);
280                                 if (dbValues [13] != null && dbValues [13] != DBNull.Value)
281                                         Scale = (byte) ((short) dbValues [13]);
282                         }
283                 }
284
285                 #endregion // Constructors
286
287                 #region Properties
288
289                 // Used to ensure that only one collection can contain this
290                 // parameter
291                 internal SqlParameterCollection Container {
292                         get { return container; }
293                         set { container = value; }
294                 }
295
296                 internal void CheckIfInitialized ()
297                 {
298                         if (!isTypeSet)
299                                 throw new Exception ("all parameters to have an explicity set type");
300
301                         if (MetaParameter.IsVariableSizeType) {
302                                 if (SqlDbType == SqlDbType.Decimal && Precision == 0)
303                                         throw new Exception ("Parameter of type 'Decimal' have an explicitly set Precision and Scale");
304                                 else if (Size == 0)
305                                         throw new Exception ("all variable length parameters to have an explicitly set non-zero Size");
306                         }
307                 }
308         
309                 public override DbType DbType {
310                         get { return dbType; }
311                         set {
312                                 SetDbType (value);
313                                 typeChanged = true;
314                                 isTypeSet = true;
315                         }
316                 }
317
318                 [RefreshProperties (RefreshProperties.All)]
319                 public override
320                 ParameterDirection Direction {
321                         get { return direction; }
322                         set { 
323                                 direction = value; 
324                                 switch( direction ) {
325                                         case ParameterDirection.Output:
326                                                 MetaParameter.Direction = TdsParameterDirection.Output;
327                                                 break;
328                                         case ParameterDirection.InputOutput:
329                                                 MetaParameter.Direction = TdsParameterDirection.InputOutput;
330                                                 break;
331                                         case ParameterDirection.ReturnValue:
332                                                 MetaParameter.Direction = TdsParameterDirection.ReturnValue;
333                                                 break;
334                                 }
335                         }
336                 }
337
338                 internal TdsMetaParameter MetaParameter {
339                         get { return metaParameter; }
340                 }
341
342                 public override bool IsNullable {
343                         get { return metaParameter.IsNullable; }
344                         set { metaParameter.IsNullable = value; }
345                 }
346
347                 [Browsable (false)]
348                 [EditorBrowsable (EditorBrowsableState.Advanced)]
349                 public int Offset {
350                         get { return offset; }
351                         set { offset = value; }
352                 }
353         
354                 public override string ParameterName {
355                         get { return metaParameter.ParameterName; }
356                         set {
357                                 if (value == null)
358                                         value = string.Empty;
359                                 metaParameter.ParameterName = value;
360                         }
361                 }
362
363                 [DefaultValue (0)]
364                 public byte Precision {
365                         get { return metaParameter.Precision; }
366                         set { metaParameter.Precision = value; }
367                 }
368
369                 [DefaultValue (0)]
370                 public byte Scale {
371                         get { return metaParameter.Scale; }
372                         set { metaParameter.Scale = value; }
373                 }
374
375                 public override int Size {
376                         get { return metaParameter.Size; }
377                         set { metaParameter.Size = value; }
378                 }
379
380                 public override string SourceColumn {
381                         get {
382                                 if (sourceColumn == null)
383                                         return string.Empty;
384                                 return sourceColumn;
385                         }
386                         set { sourceColumn = value; }
387                 }
388
389                 public override DataRowVersion SourceVersion {
390                         get { return sourceVersion; }
391                         set { sourceVersion = value; }
392                 }
393                 
394                 [RefreshProperties (RefreshProperties.All)]
395                 [DbProviderSpecificTypeProperty(true)]
396                 public SqlDbType SqlDbType {
397                         get { return sqlDbType; }
398                         set {
399                                 SetSqlDbType (value);
400                                 typeChanged = true;
401                                 isTypeSet = true;
402                         }
403                 }
404
405                 [TypeConverterAttribute (typeof (StringConverter))]
406                 [RefreshProperties (RefreshProperties.All)]
407                 public override object Value {
408                         get {
409                                 if (sqlType != null)
410                                         return GetSqlValue (metaParameter.RawValue);
411                                 return metaParameter.RawValue;
412                         }
413                         set {
414                                 if (!isTypeSet) {
415                                         InferSqlType (value);
416                                 }
417
418                                 if (value is INullable) {
419                                         sqlType = value.GetType ();
420                                         value = SqlTypeToFrameworkType (value);
421                                 }
422                                 metaParameter.RawValue = value;
423                         }
424                 }
425
426                 [Browsable (false)]
427                 public SqlCompareOptions CompareInfo{
428                         get{ return compareInfo; }
429                         set{ compareInfo = value; }
430                 }
431
432                 [Browsable (false)]
433                 public int LocaleId { 
434                         get { return localeId; }
435                         set { localeId = value; }
436                 }
437
438                 [Browsable (false)]
439                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
440                 public Object SqlValue {
441                         get {
442                                 return GetSqlValue (metaParameter.RawValue);
443                         }
444                         set {
445                                 Value = value;
446                         }
447                 }
448         
449                 public override bool SourceColumnNullMapping {
450                         get { return sourceColumnNullMapping; }
451                         set { sourceColumnNullMapping = value; }
452                 }
453
454                 public string XmlSchemaCollectionDatabase {
455                         get { return xmlSchemaCollectionDatabase; }
456                         set { xmlSchemaCollectionDatabase = (value == null ? String.Empty : value); }
457                 }
458
459                 public string XmlSchemaCollectionName {
460                         get { return xmlSchemaCollectionName; }
461                         set {
462                                 xmlSchemaCollectionName = (value == null ? String.Empty : value);
463                         }
464                 }
465
466                 public string XmlSchemaCollectionOwningSchema {
467                         get { return xmlSchemaCollectionOwningSchema; } 
468                         set {
469                                 xmlSchemaCollectionOwningSchema = (value == null ? String.Empty : value);
470                         }
471                 }
472
473                 [BrowsableAttribute(false)]
474                 public string UdtTypeName { get; set; }
475
476                 #endregion // Properties
477
478                 #region Methods
479
480                 object ICloneable.Clone ()
481                 {
482                         return new SqlParameter (ParameterName, SqlDbType, Size, Direction, IsNullable, Precision, Scale, SourceColumn, SourceVersion, Value);
483                 }
484
485                 // If the value is set without the DbType/SqlDbType being set, then we
486                 // infer type information.
487                 void InferSqlType (object value)
488                 {
489                         if (value == null || value == DBNull.Value) {
490                                 SetSqlDbType (SqlDbType.NVarChar);
491                                 return;
492                         }
493
494                         Type type = value.GetType ();
495                         if (type.IsEnum)
496                                 type = Enum.GetUnderlyingType (type);
497                         object t = type_mapping [type];
498                         if (t == null)
499                                 throw new ArgumentException (String.Format ("The parameter data type of {0} is invalid.", type.FullName));
500                         SetSqlDbType ((SqlDbType) t);
501                 }
502
503 /*
504                 // Returns System.Type corresponding to the underlying SqlDbType
505                 internal override Type SystemType {
506                         get {
507                                 return (Type) DbTypeMapping [sqlDbType];
508                         }
509                 }
510
511                 internal override object FrameworkDbType {
512                         get {
513                                 return sqlDbType;
514                         }
515                         
516                         set {
517                                 object t;
518                                 try {
519                                         t = (DbType) DbTypeFromName ((string)value);
520                                         SetDbType ((DbType)t);
521                                 } catch (ArgumentException) {
522                                         t = (SqlDbType)FrameworkDbTypeFromName ((string)value);
523                                         SetSqlDbType ((SqlDbType) t);
524                                 }
525                         }
526                 }
527 */
528
529                 DbType DbTypeFromName (string name)
530                 {
531                         switch (name.ToLower ()) {
532                                 case "ansistring":
533                                         return DbType.AnsiString;
534                                 case "ansistringfixedlength":
535                                         return DbType.AnsiStringFixedLength;
536                                 case "binary": 
537                                         return DbType.Binary;
538                                 case "boolean":
539                                         return DbType.Boolean;
540                                 case "byte":
541                                         return DbType.Byte;
542                                 case "currency": 
543                                         return DbType.Currency;
544                                 case "date":
545                                         return DbType.Date;
546                                 case "datetime": 
547                                         return DbType.DateTime;
548                                 case "decimal":
549                                         return DbType.Decimal;
550                                 case "double": 
551                                         return DbType.Double;
552                                 case "guid": 
553                                         return DbType.Guid;
554                                 case "int16": 
555                                         return DbType.Int16;
556                                 case "int32": 
557                                         return DbType.Int32;
558                                 case "int64": 
559                                         return DbType.Int64;
560                                 case "object": 
561                                         return DbType.Object;
562                                 case "single": 
563                                         return DbType.Single;
564                                 case "string": 
565                                         return DbType.String;
566                                 case "stringfixedlength": 
567                                         return DbType.StringFixedLength;
568                                 case "time": 
569                                         return DbType.Time;
570                                 case "xml": 
571                                         return DbType.Xml;
572                                 default:
573                                         string exception = String.Format ("No mapping exists from {0} to a known DbType.", name);
574                                         throw new ArgumentException (exception);
575                         }
576                 }
577
578                 // When the DbType is set, we also set the SqlDbType, as well as the SQL Server
579                 // string representation of the type name.  If the DbType is not convertible
580                 // to an SqlDbType, throw an exception.
581                 private void SetDbType (DbType type)
582                 {
583                         switch (type) {
584                         case DbType.AnsiString:
585                                 MetaParameter.TypeName = "varchar";
586                                 sqlDbType = SqlDbType.VarChar;
587                                 MetaParameter.IsVariableSizeType = true;
588                                 break;
589                         case DbType.AnsiStringFixedLength:
590                                 MetaParameter.TypeName = "char";
591                                 sqlDbType = SqlDbType.Char;
592                                 MetaParameter.IsVariableSizeType = true;
593                                 break;
594                         case DbType.Binary:
595                                 MetaParameter.TypeName = "varbinary";
596                                 sqlDbType = SqlDbType.VarBinary;
597                                 MetaParameter.IsVariableSizeType = true;
598                                 break;
599                         case DbType.Boolean:
600                                 MetaParameter.TypeName = "bit";
601                                 sqlDbType = SqlDbType.Bit;
602                                 break;
603                         case DbType.Byte:
604                                 MetaParameter.TypeName = "tinyint";
605                                 sqlDbType = SqlDbType.TinyInt;
606                                 break;
607                         case DbType.Currency:
608                                 sqlDbType = SqlDbType.Money;
609                                 MetaParameter.TypeName = "money";
610                                 break;
611                         case DbType.Date:
612                         case DbType.DateTime:
613                                 MetaParameter.TypeName = "datetime";
614                                 sqlDbType = SqlDbType.DateTime;
615                                 break;
616                         case DbType.DateTime2:
617                                 MetaParameter.TypeName = "datetime2";
618                                 sqlDbType = SqlDbType.DateTime2;
619                                 break;
620                         case DbType.Decimal:
621                                 MetaParameter.TypeName = "decimal";
622                                 sqlDbType = SqlDbType.Decimal;
623                                 break;
624                         case DbType.Double:
625                                 MetaParameter.TypeName = "float";
626                                 sqlDbType = SqlDbType.Float;
627                                 break;
628                         case DbType.Guid:
629                                 MetaParameter.TypeName = "uniqueidentifier";
630                                 sqlDbType = SqlDbType.UniqueIdentifier;
631                                 break;
632                         case DbType.Int16:
633                                 MetaParameter.TypeName = "smallint";
634                                 sqlDbType = SqlDbType.SmallInt;
635                                 break;
636                         case DbType.Int32:
637                                 MetaParameter.TypeName = "int";
638                                 sqlDbType = SqlDbType.Int;
639                                 break;
640                         case DbType.Int64:
641                                 MetaParameter.TypeName = "bigint";
642                                 sqlDbType = SqlDbType.BigInt;
643                                 break;
644                         case DbType.Object:
645                                 MetaParameter.TypeName = "sql_variant";
646                                 sqlDbType = SqlDbType.Variant;
647                                 break;
648                         case DbType.Single:
649                                 MetaParameter.TypeName = "real";
650                                 sqlDbType = SqlDbType.Real;
651                                 break;
652                         case DbType.String:
653                                 MetaParameter.TypeName = "nvarchar";
654                                 sqlDbType = SqlDbType.NVarChar;
655                                 MetaParameter.IsVariableSizeType = true;
656                                 break;
657                         case DbType.StringFixedLength:
658                                 MetaParameter.TypeName = "nchar";
659                                 sqlDbType = SqlDbType.NChar;
660                                 MetaParameter.IsVariableSizeType = true;
661                                 break;
662                         case DbType.Time:
663                                 MetaParameter.TypeName = "datetime";
664                                 sqlDbType = SqlDbType.DateTime;
665                                 break;
666                                 // Handle Xml type as string
667                         case DbType.Xml:
668                                 MetaParameter.TypeName = "xml";
669                                 sqlDbType = SqlDbType.Xml;
670                                 MetaParameter.IsVariableSizeType = true;
671                                 break;
672                         default:
673                                 string exception = String.Format ("No mapping exists from DbType {0} to a known SqlDbType.", type);
674                                 throw new ArgumentException (exception);
675                         }
676                         dbType = type;
677                 }
678
679                 // Used by internal constructor which has a SQL Server typename
680                 private SqlDbType FrameworkDbTypeFromName (string dbTypeName)
681                 {
682                         switch (dbTypeName.ToLower ()) {        
683                         case "bigint":
684                                 return SqlDbType.BigInt;
685                         case "binary":
686                                 return SqlDbType.Binary;
687                         case "bit":
688                                 return SqlDbType.Bit;
689                         case "char":
690                                 return SqlDbType.Char;
691                         case "datetime":
692                                 return SqlDbType.DateTime;
693                         case "decimal":
694                                 return SqlDbType.Decimal;
695                         case "float":
696                                 return SqlDbType.Float;
697                         case "image":
698                                 return SqlDbType.Image;
699                         case "int":
700                                 return SqlDbType.Int;
701                         case "money":
702                                 return SqlDbType.Money;
703                         case "nchar":
704                                 return SqlDbType.NChar;
705                         case "ntext":
706                                 return SqlDbType.NText;
707                         case "nvarchar":
708                                 return SqlDbType.NVarChar;
709                         case "real":
710                                 return SqlDbType.Real;
711                         case "smalldatetime":
712                                 return SqlDbType.SmallDateTime;
713                         case "smallint":
714                                 return SqlDbType.SmallInt;
715                         case "smallmoney":
716                                 return SqlDbType.SmallMoney;
717                         case "text":
718                                 return SqlDbType.Text;
719                         case "timestamp":
720                                 return SqlDbType.Timestamp;
721                         case "tinyint":
722                                 return SqlDbType.TinyInt;
723                         case "uniqueidentifier":
724                                 return SqlDbType.UniqueIdentifier;
725                         case "varbinary":
726                                 return SqlDbType.VarBinary;
727                         case "varchar":
728                                 return SqlDbType.VarChar;
729                         case "sql_variant":
730                                 return SqlDbType.Variant;
731                         case "xml":
732                                 return SqlDbType.Xml;
733                         default:
734                                 return SqlDbType.Variant;
735                         }
736                 }
737
738                 // When the SqlDbType is set, we also set the DbType, as well as the SQL Server
739                 // string representation of the type name.  If the SqlDbType is not convertible
740                 // to a DbType, throw an exception.
741                 internal void SetSqlDbType (SqlDbType type)
742                 {
743                         switch (type) {
744                         case SqlDbType.BigInt:
745                                 MetaParameter.TypeName = "bigint";
746                                 dbType = DbType.Int64;
747                                 break;
748                         case SqlDbType.Binary:
749                                 MetaParameter.TypeName = "binary";
750                                 dbType = DbType.Binary;
751                                 MetaParameter.IsVariableSizeType = true;
752                                 break;
753                         case SqlDbType.Timestamp:
754                                 MetaParameter.TypeName = "timestamp";
755                                 dbType = DbType.Binary;
756                                 break;
757                         case SqlDbType.VarBinary:
758                                 MetaParameter.TypeName = "varbinary";
759                                 dbType = DbType.Binary;
760                                 MetaParameter.IsVariableSizeType = true;
761                                 break;
762                         case SqlDbType.Bit:
763                                 MetaParameter.TypeName = "bit";
764                                 dbType = DbType.Boolean;
765                                 break;
766                         case SqlDbType.Char:
767                                 MetaParameter.TypeName = "char";
768                                 dbType = DbType.AnsiStringFixedLength;
769                                 MetaParameter.IsVariableSizeType = true;
770                                 break;
771                         case SqlDbType.DateTime:
772                                 MetaParameter.TypeName = "datetime";
773                                 dbType = DbType.DateTime;
774                                 break;
775                         case SqlDbType.SmallDateTime:
776                                 MetaParameter.TypeName = "smalldatetime";
777                                 dbType = DbType.DateTime;
778                                 break;
779                         case SqlDbType.DateTime2:
780                                 MetaParameter.TypeName = "datetime2";
781                                 dbType = DbType.DateTime2;
782                                 break;
783                         case SqlDbType.DateTimeOffset:
784                                 MetaParameter.TypeName = "datetimeoffset";
785                                 dbType = DbType.DateTimeOffset;
786                                 break;
787                         case SqlDbType.Decimal:
788                                 MetaParameter.TypeName = "decimal";
789                                 dbType = DbType.Decimal;
790                                 break;
791                         case SqlDbType.Float:
792                                 MetaParameter.TypeName = "float";
793                                 dbType = DbType.Double;
794                                 break;
795                         case SqlDbType.Image:
796                                 MetaParameter.TypeName = "image";
797                                 dbType = DbType.Binary;
798                                 MetaParameter.IsVariableSizeType = true;
799                                 break;
800                         case SqlDbType.Int:
801                                 MetaParameter.TypeName = "int";
802                                 dbType = DbType.Int32;
803                                 break;
804                         case SqlDbType.Money:
805                                 MetaParameter.TypeName = "money";
806                                 dbType = DbType.Currency;
807                                 break;
808                         case SqlDbType.SmallMoney:
809                                 MetaParameter.TypeName = "smallmoney";
810                                 dbType = DbType.Currency;
811                                 break;
812                         case SqlDbType.NChar:
813                                 MetaParameter.TypeName = "nchar";
814                                 dbType = DbType.StringFixedLength;
815                                 MetaParameter.IsVariableSizeType = true;
816                                 break;
817                         case SqlDbType.NText:
818                                 MetaParameter.TypeName = "ntext";
819                                 dbType = DbType.String;
820                                 MetaParameter.IsVariableSizeType = true;
821                                 break;
822                         case SqlDbType.NVarChar:
823                                 MetaParameter.TypeName = "nvarchar";
824                                 dbType = DbType.String;
825                                 MetaParameter.IsVariableSizeType = true;
826                                 break;
827                         case SqlDbType.Real:
828                                 MetaParameter.TypeName = "real";
829                                 dbType = DbType.Single;
830                                 break;
831                         case SqlDbType.SmallInt:
832                                 MetaParameter.TypeName = "smallint";
833                                 dbType = DbType.Int16;
834                                 break;
835                         case SqlDbType.Text:
836                                 MetaParameter.TypeName = "text";
837                                 dbType = DbType.AnsiString;
838                                 MetaParameter.IsVariableSizeType = true;
839                                 break;
840                         case SqlDbType.VarChar:
841                                 MetaParameter.TypeName = "varchar";
842                                 dbType = DbType.AnsiString;
843                                 MetaParameter.IsVariableSizeType = true;
844                                 break;
845                         case SqlDbType.TinyInt:
846                                 MetaParameter.TypeName = "tinyint";
847                                 dbType = DbType.Byte;
848                                 break;
849                         case SqlDbType.UniqueIdentifier:
850                                 MetaParameter.TypeName = "uniqueidentifier";
851                                 dbType = DbType.Guid;
852                                 break;
853                         case SqlDbType.Variant:
854                                 MetaParameter.TypeName = "sql_variant";
855                                 dbType = DbType.Object;
856                                 break;
857                         case SqlDbType.Xml:
858                                 MetaParameter.TypeName = "xml";
859                                 dbType = DbType.Xml;
860                                 MetaParameter.IsVariableSizeType = true;
861                                 break;
862                         default:
863                                 string exception = String.Format ("No mapping exists from SqlDbType {0} to a known DbType.", type);
864                                 throw new ArgumentOutOfRangeException ("SqlDbType", exception);
865                         }
866                         sqlDbType = type;
867                 }
868
869                 public override string ToString() 
870                 {
871                         return ParameterName;
872                 }
873
874                 object GetFrameworkValue (object rawValue, ref bool updated)
875                 {
876                         object tdsValue;
877
878                         updated = typeChanged || updated;
879                         if (updated) {
880                                 tdsValue = SqlTypeToFrameworkType (rawValue);
881                                 typeChanged = false;
882                         } else
883                                 tdsValue = null;
884                         return tdsValue;
885                 }
886                 
887                 // TODO: Code copied from SqlDataReader, need a better approach
888                 object GetSqlValue (object value)
889                 {               
890                         if (value == null)
891                                 return value;
892                         switch (sqlDbType) {
893                         case SqlDbType.BigInt:
894                                 if (value == DBNull.Value)
895                                         return SqlInt64.Null;
896                                 return (SqlInt64) ((long) value);
897                         case SqlDbType.Binary:
898                         case SqlDbType.Image:
899                         case SqlDbType.VarBinary:
900                         case SqlDbType.Timestamp:
901                                 if (value == DBNull.Value)
902                                         return SqlBinary.Null;
903                                 return (SqlBinary) (byte[]) value;
904                         case SqlDbType.Bit:
905                                 if (value == DBNull.Value)
906                                         return SqlBoolean.Null;
907                                 return (SqlBoolean) ((bool) value);
908                         case SqlDbType.Char:
909                         case SqlDbType.NChar:
910                         case SqlDbType.NText:
911                         case SqlDbType.NVarChar:
912                         case SqlDbType.Text:
913                         case SqlDbType.VarChar:
914                                 if (value == DBNull.Value)
915                                         return SqlString.Null;
916
917                                 string str;
918                                 Type type = value.GetType ();
919                                 if (type == typeof (char))
920                                         str = value.ToString ();
921                                 else if (type == typeof (char[]))
922                                         str = new String ((char[])value);
923                                 else
924                                         str = ((string)value);
925                                         return (SqlString) str;
926                         case SqlDbType.DateTime:
927                         case SqlDbType.SmallDateTime:
928                                 if (value == DBNull.Value)
929                                         return SqlDateTime.Null;
930                                 return (SqlDateTime) ((DateTime) value);
931                         case SqlDbType.Decimal:
932                                 if (value == DBNull.Value)
933                                         return SqlDecimal.Null;
934                                 if (value is TdsBigDecimal)
935                                         return SqlDecimalExtensions.FromTdsBigDecimal ((TdsBigDecimal) value);
936                                 return (SqlDecimal) ((decimal) value);
937                         case SqlDbType.Float:
938                                 if (value == DBNull.Value)
939                                         return SqlDouble.Null;
940                                 return (SqlDouble) ((double) value);
941                         case SqlDbType.Int:
942                                 if (value == DBNull.Value)
943                                         return SqlInt32.Null;
944                                 return (SqlInt32) ((int) value);
945                         case SqlDbType.Money:
946                         case SqlDbType.SmallMoney:
947                                 if (value == DBNull.Value)
948                                         return SqlMoney.Null;
949                                 return (SqlMoney) ((decimal) value);
950                         case SqlDbType.Real:
951                                 if (value == DBNull.Value)
952                                         return SqlSingle.Null;
953                                 return (SqlSingle) ((float) value);
954                         case SqlDbType.UniqueIdentifier:
955                                 if (value == DBNull.Value)
956                                         return SqlGuid.Null;
957                                 return (SqlGuid) ((Guid) value);
958                         case SqlDbType.SmallInt:
959                                 if (value == DBNull.Value)
960                                         return SqlInt16.Null;
961                                 return (SqlInt16) ((short) value);
962                         case SqlDbType.TinyInt:
963                                 if (value == DBNull.Value)
964                                         return SqlByte.Null;
965                                 return (SqlByte) ((byte) value);
966                         case SqlDbType.Xml:
967                                 if (value == DBNull.Value)
968                                         return SqlXml.Null;
969                                 return (SqlXml) value;
970                         default:
971                                 throw new NotImplementedException ("Type '" + sqlDbType + "' not implemented.");
972                         }
973                 }
974                 
975                 object SqlTypeToFrameworkType (object value)
976                 {
977                         INullable nullable = value as INullable;
978                         if (nullable == null)
979                                 return ConvertToFrameworkType (value);
980
981                         if (nullable.IsNull)
982                                 return DBNull.Value;
983
984                         Type type = value.GetType ();
985                         // Map to .net type, as Mono TDS respects only types from .net
986
987                         if (typeof (SqlString) == type) {
988                                 return ((SqlString) value).Value;
989                         }
990
991                         if (typeof (SqlInt16) == type) {
992                                 return ((SqlInt16) value).Value;
993                         }
994
995                         if (typeof (SqlInt32) == type) {
996                                 return ((SqlInt32) value).Value;
997                         }
998
999                         if (typeof (SqlDateTime) == type) {
1000                                 return ((SqlDateTime) value).Value;
1001                         }
1002
1003                         if (typeof (SqlInt64) == type) {
1004                                 return ((SqlInt64) value).Value;
1005                         }
1006
1007                         if (typeof (SqlBinary) == type) {
1008                                 return ((SqlBinary) value).Value;
1009                         }
1010                         
1011                         if (typeof (SqlBytes) == type) {
1012                                 return ((SqlBytes) value).Value;
1013                         }
1014
1015                         if (typeof (SqlChars) == type) {
1016                                 return ((SqlChars) value).Value;
1017                         }
1018
1019                         if (typeof (SqlBoolean) == type) {
1020                                 return ((SqlBoolean) value).Value;
1021                         }
1022
1023                         if (typeof (SqlByte) == type) {
1024                                 return ((SqlByte) value).Value;
1025                         }
1026
1027                         if (typeof (SqlDecimal) == type) {
1028                                 return ((SqlDecimal) value).Value;
1029                         }
1030
1031                         if (typeof (SqlDouble) == type) {
1032                                 return ((SqlDouble) value).Value;
1033                         }
1034
1035                         if (typeof (SqlGuid) == type) {
1036                                 return ((SqlGuid) value).Value;
1037                         }
1038
1039                         if (typeof (SqlMoney) == type) {
1040                                 return ((SqlMoney) value).Value;
1041                         }
1042
1043                         if (typeof (SqlSingle) == type) {
1044                                 return ((SqlSingle) value).Value;
1045                         }
1046
1047                         return value;
1048                 }
1049
1050                 internal object ConvertToFrameworkType (object value)
1051                 {
1052                         if (value == null || value == DBNull.Value)
1053                                 return value;
1054                         if (sqlDbType == SqlDbType.Variant)
1055                                 return metaParameter.Value;
1056
1057                         Type frameworkType = SystemType;
1058                         if (frameworkType == null)
1059                                 throw new NotImplementedException ("Type Not Supported : " + sqlDbType.ToString());
1060
1061                         Type valueType = value.GetType ();
1062                         if (valueType == frameworkType)
1063                                 return value;
1064
1065                         object sqlvalue = null;
1066
1067                         try {
1068                                 sqlvalue = ConvertToFrameworkType (value, frameworkType);
1069                         } catch (FormatException ex) {
1070                                 throw new FormatException (string.Format (CultureInfo.InvariantCulture,
1071                                         "Parameter value could not be converted from {0} to {1}.",
1072                                         valueType.Name, frameworkType.Name), ex);
1073                         }
1074
1075                         return sqlvalue;
1076                 }
1077
1078                 object ConvertToFrameworkType (object value, Type frameworkType)
1079                 {
1080                         if (frameworkType == typeof (string)) {
1081                                 if (value is DateTime)
1082                                         return ((DateTime) value).ToString ("yyyy-MM-dd'T'HH':'mm':'ss.fffffff");
1083                                 if (value is DateTimeOffset)
1084                                         return ((DateTimeOffset) value).ToString ("yyyy-MM-dd'T'HH':'mm':'ss.fffffffzzz");
1085                         }
1086
1087                         object sqlvalue = Convert.ChangeType (value, frameworkType);
1088                         switch (sqlDbType) {
1089                         case SqlDbType.Money:
1090                         case SqlDbType.SmallMoney:
1091                                 sqlvalue = Decimal.Round ((decimal) sqlvalue, 4);
1092                                 break;
1093                         }
1094                         return sqlvalue;
1095                 }
1096
1097                 public override void ResetDbType ()
1098                 {
1099                         InferSqlType (Value);
1100                 }
1101
1102                 public void ResetSqlDbType ()
1103                 {
1104                         InferSqlType (Value);
1105                 }
1106
1107                 #endregion // Methods
1108         }
1109 }