Add license and copyright to all source files in System.Data
[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 //
10 // (C) Ximian, Inc. 2002
11 // Copyright (C) Tim Coleman, 2002
12 //
13
14 //
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
24 // 
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
27 // 
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 //
36
37 using Mono.Data.Tds;
38 using Mono.Data.Tds.Protocol;
39 using System;
40 using System.ComponentModel;
41 using System.Data;
42 using System.Data.Common;
43 using System.Runtime.InteropServices;
44 using System.Text;
45
46 namespace System.Data.SqlClient {
47         [TypeConverterAttribute (typeof (SqlParameterConverter))]
48         public sealed class SqlParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
49         {
50                 #region Fields
51
52                 TdsMetaParameter metaParameter;
53
54                 SqlParameterCollection container = null;
55                 DbType dbType;
56                 ParameterDirection direction = ParameterDirection.Input;
57                 bool isNullable;
58                 bool isSizeSet = false;
59                 bool isTypeSet = false;
60                 int offset;
61                 SqlDbType sqlDbType;
62                 string sourceColumn;
63                 DataRowVersion sourceVersion;
64
65                 #endregion // Fields
66
67                 #region Constructors
68
69                 public SqlParameter () 
70                         : this (String.Empty, SqlDbType.NVarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
71                 {
72                 }
73
74                 public SqlParameter (string parameterName, object value) 
75                 {
76                         metaParameter = new TdsMetaParameter (parameterName, value);
77                         this.sourceVersion = DataRowVersion.Current;
78                         InferSqlType (value);
79                 }
80                 
81                 public SqlParameter (string parameterName, SqlDbType dbType) 
82                         : this (parameterName, dbType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
83                 {
84                 }
85
86                 public SqlParameter (string parameterName, SqlDbType dbType, int size) 
87                         : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
88                 {
89                 }
90                 
91                 public SqlParameter (string parameterName, SqlDbType dbType, int size, string sourceColumn) 
92                         : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, sourceColumn, DataRowVersion.Current, null)
93                 {
94                 }
95                 
96                 [EditorBrowsable (EditorBrowsableState.Advanced)]        
97                 public SqlParameter (string parameterName, SqlDbType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value) 
98                 {
99                         metaParameter = new TdsMetaParameter (parameterName, size, isNullable, precision, scale, value);
100
101                         SqlDbType = dbType;
102                         Direction = direction;
103                         SourceColumn = sourceColumn;
104                         SourceVersion = sourceVersion;
105                 }
106
107                 // This constructor is used internally to construct a
108                 // SqlParameter.  The value array comes from sp_procedure_params_rowset.
109                 // This is in SqlCommand.DeriveParameters.
110                 internal SqlParameter (object[] dbValues)
111                 {
112                         Precision = 0;
113                         Scale = 0;
114                         Direction = ParameterDirection.Input;
115
116                         ParameterName = (string) dbValues[3];
117
118                         switch ((short) dbValues[5]) {
119                         case 1:
120                                 Direction = ParameterDirection.Input;
121                                 break;
122                         case 2:
123                                 Direction = ParameterDirection.Output;
124                                 break;
125                         case 3:
126                                 Direction = ParameterDirection.InputOutput;
127                                 break;
128                         case 4:
129                                 Direction = ParameterDirection.ReturnValue;
130                                 break;
131                         }
132
133                         IsNullable = (bool) dbValues[8];
134
135                         if (dbValues[12] != null)
136                                 Precision = (byte) ((short) dbValues[12]);
137                         if (dbValues[13] != null)
138                                 Scale = (byte) ((short) dbValues[13]);
139
140                         SetDbTypeName ((string) dbValues[16]);
141                 }
142
143                 #endregion // Constructors
144
145                 #region Properties
146
147                 // Used to ensure that only one collection can contain this
148                 // parameter
149                 internal SqlParameterCollection Container {
150                         get { return container; }
151                         set { container = value; }
152                 }
153
154                 [Browsable (false)]
155                 [DataCategory ("Data")]
156                 [DataSysDescription ("The parameter generic type.")]
157                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
158                 [RefreshProperties (RefreshProperties.All)]
159                 public DbType DbType {
160                         get { return dbType; }
161                         set { 
162                                 SetDbType (value); 
163                                 isTypeSet = true;
164                         }
165                 }
166
167                 [DataCategory ("Data")]
168                 [DataSysDescription ("Input, output, or bidirectional parameter.")]
169                 [DefaultValue (ParameterDirection.Input)]
170                 public ParameterDirection Direction {
171                         get { return direction; }
172                         set { 
173                                 direction = value; 
174                                 switch( direction ) {
175                                         case ParameterDirection.Output:
176                                         MetaParameter.Direction = TdsParameterDirection.Output;
177                                                 break;
178                                         case ParameterDirection.InputOutput:
179                                                 MetaParameter.Direction = TdsParameterDirection.InputOutput;
180                                                 break;
181                                         case ParameterDirection.ReturnValue:
182                                                 MetaParameter.Direction = TdsParameterDirection.ReturnValue;
183                                                 break;
184                                 }
185                         }
186                 }
187
188                 internal TdsMetaParameter MetaParameter {
189                         get { return metaParameter; }
190                 }
191
192                 string IDataParameter.ParameterName {
193                         get { return metaParameter.ParameterName; }
194                         set { metaParameter.ParameterName = value; }
195                 }
196
197                 [Browsable (false)]
198                 [DataSysDescription ("a design-time property used for strongly typed code-generation.")]
199                 [DefaultValue (false)]
200                 [DesignOnly (true)]
201                 [EditorBrowsable (EditorBrowsableState.Advanced)]        
202                 public bool IsNullable  {
203                         get { return metaParameter.IsNullable; }
204                         set { metaParameter.IsNullable = value; }
205                 }
206
207                 [Browsable (false)]
208                 [DataCategory ("Data")]
209                 [DataSysDescription ("Offset in variable length data types.")]
210                 [DefaultValue (0)]
211                 public int Offset {
212                         get { return offset; }
213                         set { offset = value; }
214                 }
215                 
216                 [DataSysDescription ("Name of the parameter, like '@p1'")]
217                 [DefaultValue ("")]
218                 public string ParameterName {
219                         get { return metaParameter.ParameterName; }
220                         set { metaParameter.ParameterName = value; }
221                 }
222
223                 [DataCategory ("Data")]
224                 [DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
225                 [DefaultValue (0)]
226                 public byte Precision {
227                         get { return metaParameter.Precision; }
228                         set { metaParameter.Precision = value; }
229                 }
230
231                 [DataCategory ("Data")]
232                 [DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
233                 [DefaultValue (0)]
234                 public byte Scale {
235                         get { return metaParameter.Scale; }
236                         set { metaParameter.Scale = value; }
237                 }
238
239                 [DataCategory ("Data")]
240                 [DataSysDescription ("Size of variable length datatypes (strings & arrays).")]
241                 [DefaultValue (0)]
242                 public int Size {
243                         get { return metaParameter.Size; }
244                         set { metaParameter.Size = value; }
245                 }
246
247                 [DataCategory ("Data")]
248                 [DataSysDescription ("When used by a DataAdapter.Update, the source column name that is used to find the DataSetColumn name in the ColumnMappings. This is to copy a value between the parameter and a datarow.")]
249                 [DefaultValue ("")]
250                 public string SourceColumn {
251                         get { return sourceColumn; }
252                         set { sourceColumn = value; }
253                 }
254
255                 [DataCategory ("Data")]
256                 [DataSysDescription ("When used by a DataAdapter.Update (UpdateCommand only), the version of the DataRow value that is used to update the data source.")]
257                 [DefaultValue (DataRowVersion.Current)]
258                 public DataRowVersion SourceVersion {
259                         get { return sourceVersion; }
260                         set { sourceVersion = value; }
261                 }
262                 
263                 [DataCategory ("Data")]
264                 [DataSysDescription ("The parameter native type.")]
265                 [DefaultValue (SqlDbType.NVarChar)]
266                 [RefreshProperties (RefreshProperties.All)]
267                 public SqlDbType SqlDbType {
268                         get { return sqlDbType; }
269                         set { 
270                                 SetSqlDbType (value); 
271                                 isTypeSet = true;
272                         }
273                 }
274
275                 [DataCategory ("Data")]
276                 [DataSysDescription ("Value of the parameter.")]
277                 [DefaultValue (null)]
278                 [TypeConverterAttribute (typeof (StringConverter))]
279                 public object Value {
280                         get { return metaParameter.Value; }
281                         set { 
282                                 if (!isTypeSet)
283                                         InferSqlType (value);
284                                 metaParameter.Value = value; 
285                         }
286                 }
287
288                 #endregion // Properties
289
290                 #region Methods
291
292                 object ICloneable.Clone ()
293                 {
294                         return new SqlParameter (ParameterName, SqlDbType, Size, Direction, IsNullable, Precision, Scale, SourceColumn, SourceVersion, Value);
295                 }
296
297                 // If the value is set without the DbType/SqlDbType being set, then we
298                 // infer type information.
299                 private void InferSqlType (object value)
300                 {
301                         Type type = value.GetType ();
302
303                         string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
304
305                         switch (type.FullName) {
306                         case "System.Int64":
307                                 SetSqlDbType (SqlDbType.BigInt);
308                                 break;
309                         case "System.Boolean":
310                                 SetSqlDbType (SqlDbType.Bit);
311                                 break;
312                         case "System.String":
313                                 SetSqlDbType (SqlDbType.NVarChar);
314                                 break;
315                         case "System.DateTime":
316                                 SetSqlDbType (SqlDbType.DateTime);
317                                 break;
318                         case "System.Decimal":
319                                 SetSqlDbType (SqlDbType.Decimal);
320                                 break;
321                         case "System.Double":
322                                 SetSqlDbType (SqlDbType.Float);
323                                 break;
324                         case "System.Byte[]":
325                                 SetSqlDbType (SqlDbType.VarBinary);
326                                 break;
327                         case "System.Byte":
328                                 SetSqlDbType (SqlDbType.TinyInt);
329                                 break;
330                         case "System.Int32":
331                                 SetSqlDbType (SqlDbType.Int);
332                                 break;
333                         case "System.Single":
334                                 SetSqlDbType (SqlDbType.Real);
335                                 break;
336                         case "System.Int16":
337                                 SetSqlDbType (SqlDbType.SmallInt);
338                                 break;
339                         case "System.Guid":
340                                 SetSqlDbType (SqlDbType.UniqueIdentifier);
341                                 break;
342                         case "System.Object":
343                                 SetSqlDbType (SqlDbType.Variant);
344                                 break;
345                         default:
346                                 throw new ArgumentException (exception);                                
347                         }
348                 }
349
350                 // When the DbType is set, we also set the SqlDbType, as well as the SQL Server
351                 // string representation of the type name.  If the DbType is not convertible
352                 // to an SqlDbType, throw an exception.
353                 private void SetDbType (DbType type)
354                 {
355                         string exception = String.Format ("No mapping exists from DbType {0} to a known SqlDbType.", type);
356
357                         switch (type) {
358                         case DbType.AnsiString:
359                                 MetaParameter.TypeName = "varchar";
360                                 sqlDbType = SqlDbType.VarChar;
361                                 break;
362                         case DbType.AnsiStringFixedLength:
363                                 MetaParameter.TypeName = "char";
364                                 sqlDbType = SqlDbType.Char;
365                                 break;
366                         case DbType.Binary:
367                                 MetaParameter.TypeName = "varbinary";
368                                 sqlDbType = SqlDbType.VarBinary;
369                                 break;
370                         case DbType.Boolean:
371                                 MetaParameter.TypeName = "bit";
372                                 sqlDbType = SqlDbType.Bit;
373                                 break;
374                         case DbType.Byte:
375                                 MetaParameter.TypeName = "tinyint";
376                                 sqlDbType = SqlDbType.TinyInt;
377                                 break;
378                         case DbType.Currency:
379                                 sqlDbType = SqlDbType.Money;
380                                 MetaParameter.TypeName = "money";
381                                 break;
382                         case DbType.Date:
383                         case DbType.DateTime:
384                                 MetaParameter.TypeName = "datetime";
385                                 sqlDbType = SqlDbType.DateTime;
386                                 break;
387                         case DbType.Decimal:
388                                 MetaParameter.TypeName = "decimal";
389                                 sqlDbType = SqlDbType.Decimal;
390                                 break;
391                         case DbType.Double:
392                                 MetaParameter.TypeName = "float";
393                                 sqlDbType = SqlDbType.Float;
394                                 break;
395                         case DbType.Guid:
396                                 MetaParameter.TypeName = "uniqueidentifier";
397                                 sqlDbType = SqlDbType.UniqueIdentifier;
398                                 break;
399                         case DbType.Int16:
400                                 MetaParameter.TypeName = "smallint";
401                                 sqlDbType = SqlDbType.SmallInt;
402                                 break;
403                         case DbType.Int32:
404                                 MetaParameter.TypeName = "int";
405                                 sqlDbType = SqlDbType.Int;
406                                 break;
407                         case DbType.Int64:
408                                 MetaParameter.TypeName = "bigint";
409                                 sqlDbType = SqlDbType.BigInt;
410                                 break;
411                         case DbType.Object:
412                                 MetaParameter.TypeName = "sql_variant";
413                                 sqlDbType = SqlDbType.Variant;
414                                 break;
415                         case DbType.Single:
416                                 MetaParameter.TypeName = "real";
417                                 sqlDbType = SqlDbType.Real;
418                                 break;
419                         case DbType.String:
420                                 MetaParameter.TypeName = "nvarchar";
421                                 sqlDbType = SqlDbType.NVarChar;
422                                 break;
423                         case DbType.StringFixedLength:
424                                 MetaParameter.TypeName = "nchar";
425                                 sqlDbType = SqlDbType.NChar;
426                                 break;
427                         case DbType.Time:
428                                 MetaParameter.TypeName = "datetime";
429                                 sqlDbType = SqlDbType.DateTime;
430                                 break;
431                         default:
432                                 throw new ArgumentException (exception);
433                         }
434                         dbType = type;
435                 }
436
437                 // Used by internal constructor which has a SQL Server typename
438                 private void SetDbTypeName (string dbTypeName)
439                 {
440                         switch (dbTypeName.ToLower ()) {        
441                         case "bigint":
442                                 SqlDbType = SqlDbType.BigInt;
443                                 break;
444                         case "binary":
445                                 SqlDbType = SqlDbType.Binary;
446                                 break;
447                         case "bit":
448                                 SqlDbType = SqlDbType.Bit;
449                                 break;
450                         case "char":
451                                 SqlDbType = SqlDbType.Char;
452                                 break;
453                         case "datetime":
454                                 SqlDbType = SqlDbType.DateTime;
455                                 break;
456                         case "decimal":
457                                 SqlDbType = SqlDbType.Decimal;
458                                 break;
459                         case "float":
460                                 SqlDbType = SqlDbType.Float;
461                                 break;
462                         case "image":
463                                 SqlDbType = SqlDbType.Image;
464                                 break;
465                         case "int":
466                                 SqlDbType = SqlDbType.Int;
467                                 break;
468                         case "money":
469                                 SqlDbType = SqlDbType.Money;
470                                 break;
471                         case "nchar":
472                                 SqlDbType = SqlDbType.NChar;
473                                 break;
474                         case "ntext":
475                                 SqlDbType = SqlDbType.NText;
476                                 break;
477                         case "nvarchar":
478                                 SqlDbType = SqlDbType.NVarChar;
479                                 break;
480                         case "real":
481                                 SqlDbType = SqlDbType.Real;
482                                 break;
483                         case "smalldatetime":
484                                 SqlDbType = SqlDbType.SmallDateTime;
485                                 break;
486                         case "smallint":
487                                 SqlDbType = SqlDbType.SmallInt;
488                                 break;
489                         case "smallmoney":
490                                 SqlDbType = SqlDbType.SmallMoney;
491                                 break;
492                         case "text":
493                                 SqlDbType = SqlDbType.Text;
494                                 break;
495                         case "timestamp":
496                                 SqlDbType = SqlDbType.Timestamp;
497                                 break;
498                         case "tinyint":
499                                 SqlDbType = SqlDbType.TinyInt;
500                                 break;
501                         case "uniqueidentifier":
502                                 SqlDbType = SqlDbType.UniqueIdentifier;
503                                 break;
504                         case "varbinary":
505                                 SqlDbType = SqlDbType.VarBinary;
506                                 break;
507                         case "varchar":
508                                 SqlDbType = SqlDbType.VarChar;
509                                 break;
510                         default:
511                                 SqlDbType = SqlDbType.Variant;
512                                 break;
513                         }
514                 }
515
516                 // When the SqlDbType is set, we also set the DbType, as well as the SQL Server
517                 // string representation of the type name.  If the SqlDbType is not convertible
518                 // to a DbType, throw an exception.
519                 private void SetSqlDbType (SqlDbType type)
520                 {
521                         string exception = String.Format ("No mapping exists from SqlDbType {0} to a known DbType.", type);
522
523                         switch (type) {
524                         case SqlDbType.BigInt:
525                                 MetaParameter.TypeName = "bigint";
526                                 dbType = DbType.Int64;
527                                 break;
528                         case SqlDbType.Binary:
529                                 MetaParameter.TypeName = "binary";
530                                 dbType = DbType.Binary;
531                                 break;
532                         case SqlDbType.Timestamp:
533                                 MetaParameter.TypeName = "timestamp";
534                                 dbType = DbType.Binary;
535                                 break;
536                         case SqlDbType.VarBinary:
537                                 MetaParameter.TypeName = "varbinary";
538                                 dbType = DbType.Binary;
539                                 break;
540                         case SqlDbType.Bit:
541                                 MetaParameter.TypeName = "bit";
542                                 dbType = DbType.Boolean;
543                                 break;
544                         case SqlDbType.Char:
545                                 MetaParameter.TypeName = "char";
546                                 dbType = DbType.AnsiStringFixedLength;
547                                 break;
548                         case SqlDbType.DateTime:
549                                 MetaParameter.TypeName = "datetime";
550                                 dbType = DbType.DateTime;
551                                 break;
552                         case SqlDbType.SmallDateTime:
553                                 MetaParameter.TypeName = "smalldatetime";
554                                 dbType = DbType.DateTime;
555                                 break;
556                         case SqlDbType.Decimal:
557                                 MetaParameter.TypeName = "decimal";
558                                 dbType = DbType.Decimal;
559                                 break;
560                         case SqlDbType.Float:
561                                 MetaParameter.TypeName = "float";
562                                 dbType = DbType.Double;
563                                 break;
564                         case SqlDbType.Image:
565                                 MetaParameter.TypeName = "image";
566                                 dbType = DbType.Binary;
567                                 break;
568                         case SqlDbType.Int:
569                                 MetaParameter.TypeName = "int";
570                                 dbType = DbType.Int32;
571                                 break;
572                         case SqlDbType.Money:
573                                 MetaParameter.TypeName = "money";
574                                 dbType = DbType.Currency;
575                                 break;
576                         case SqlDbType.SmallMoney:
577                                 MetaParameter.TypeName = "smallmoney";
578                                 dbType = DbType.Currency;
579                                 break;
580                         case SqlDbType.NChar:
581                                 MetaParameter.TypeName = "nchar";
582                                 dbType = DbType.StringFixedLength;
583                                 break;
584                         case SqlDbType.NText:
585                                 MetaParameter.TypeName = "ntext";
586                                 dbType = DbType.String;
587                                 break;
588                         case SqlDbType.NVarChar:
589                                 MetaParameter.TypeName = "nvarchar";
590                                 dbType = DbType.String;
591                                 break;
592                         case SqlDbType.Real:
593                                 MetaParameter.TypeName = "real";
594                                 dbType = DbType.Single;
595                                 break;
596                         case SqlDbType.SmallInt:
597                                 MetaParameter.TypeName = "smallint";
598                                 dbType = DbType.Int16;
599                                 break;
600                         case SqlDbType.Text:
601                                 MetaParameter.TypeName = "text";
602                                 dbType = DbType.AnsiString;
603                                 break;
604                         case SqlDbType.VarChar:
605                                 MetaParameter.TypeName = "varchar";
606                                 dbType = DbType.AnsiString;
607                                 break;
608                         case SqlDbType.TinyInt:
609                                 MetaParameter.TypeName = "tinyint";
610                                 dbType = DbType.Byte;
611                                 break;
612                         case SqlDbType.UniqueIdentifier:
613                                 MetaParameter.TypeName = "uniqueidentifier";
614                                 dbType = DbType.Guid;
615                                 break;
616                         case SqlDbType.Variant:
617                                 MetaParameter.TypeName = "sql_variant";
618                                 dbType = DbType.Object;
619                                 break;
620                         default:
621                                 throw new ArgumentException (exception);
622                         }
623                         sqlDbType = type;
624                 }
625
626                 public override string ToString() 
627                 {
628                         return ParameterName;
629                 }
630
631                 #endregion // Methods
632         }
633 }