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