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