2 // System.Data.SqlClient.SqlParameter.cs
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)
11 // (C) Ximian, Inc. 2002
12 // Copyright (C) Tim Coleman, 2002
16 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
18 // Permission is hereby granted, free of charge, to any person obtaining
19 // a copy of this software and associated documentation files (the
20 // "Software"), to deal in the Software without restriction, including
21 // without limitation the rights to use, copy, modify, merge, publish,
22 // distribute, sublicense, and/or sell copies of the Software, and to
23 // permit persons to whom the Software is furnished to do so, subject to
24 // the following conditions:
26 // The above copyright notice and this permission notice shall be
27 // included in all copies or substantial portions of the Software.
29 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 using Mono.Data.Tds.Protocol;
41 using System.ComponentModel;
43 using System.Data.Common;
45 using System.Data.ProviderBase;
47 using System.Data.SqlTypes;
48 using System.Runtime.InteropServices;
51 namespace System.Data.SqlClient {
52 [TypeConverterAttribute (typeof (SqlParameterConverter))]
54 public sealed class SqlParameter : DbParameterBase, IDbDataParameter, IDataParameter, ICloneable
56 public sealed class SqlParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
61 TdsMetaParameter metaParameter;
63 SqlParameterCollection container = null;
65 ParameterDirection direction = ParameterDirection.Input;
67 bool isVariableSizeType = false;
68 bool isTypeSet = false;
72 DataRowVersion sourceVersion;
78 public SqlParameter ()
79 : this (String.Empty, SqlDbType.NVarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
84 public SqlParameter (string parameterName, object value)
86 metaParameter = new TdsMetaParameter (parameterName, SqlTypeToFrameworkType (value));
87 this.sourceVersion = DataRowVersion.Current;
91 public SqlParameter (string parameterName, SqlDbType dbType)
92 : this (parameterName, dbType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
96 public SqlParameter (string parameterName, SqlDbType dbType, int size)
97 : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
101 public SqlParameter (string parameterName, SqlDbType dbType, int size, string sourceColumn)
102 : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, sourceColumn, DataRowVersion.Current, null)
106 [EditorBrowsable (EditorBrowsableState.Advanced)]
107 public SqlParameter (string parameterName, SqlDbType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value)
109 metaParameter = new TdsMetaParameter (parameterName, size,
110 isNullable, precision,
112 SqlTypeToFrameworkType (value));
114 Direction = direction;
115 SourceColumn = sourceColumn;
116 SourceVersion = sourceVersion;
119 // This constructor is used internally to construct a
120 // SqlParameter. The value array comes from sp_procedure_params_rowset.
121 // This is in SqlCommand.DeriveParameters.
122 internal SqlParameter (object[] dbValues)
123 : this (dbValues [3].ToString (), String.Empty)
127 Direction = ParameterDirection.Input;
129 ParameterName = (string) dbValues[3];
131 switch ((short) dbValues[5]) {
133 Direction = ParameterDirection.Input;
136 Direction = ParameterDirection.Output;
139 Direction = ParameterDirection.InputOutput;
142 Direction = ParameterDirection.ReturnValue;
145 Direction = ParameterDirection.Input;
148 IsNullable = (dbValues [8] != null &&
149 dbValues [8] != DBNull.Value) ? (bool) dbValues [8] : false;
151 if (dbValues [12] != null && dbValues [12] != DBNull.Value)
152 Precision = (byte) ((short) dbValues [12]);
154 if (dbValues [13] != null && dbValues [13] != DBNull.Value)
155 Scale = (byte) ( (short) dbValues [13]);
157 SetDbTypeName ((string) dbValues [16]);
160 #endregion // Constructors
164 // Used to ensure that only one collection can contain this
166 internal SqlParameterCollection Container {
167 get { return container; }
168 set { container = value; }
171 internal void CheckIfInitialized ()
174 throw new Exception ("all parameters to have an explicity set type");
176 if (isVariableSizeType) {
177 if (SqlDbType == SqlDbType.Decimal && Precision == 0)
178 throw new Exception ("Parameter of type 'Decimal' have an explicitly set Precision and Scale");
180 throw new Exception ("all variable length parameters to have an explicitly set non-zero Size");
184 #if ONLY_1_0 || ONLY_1_1
186 [DataSysDescription ("The parameter generic type.")]
187 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
188 [RefreshProperties (RefreshProperties.All)]
190 [DataCategory ("Data")]
196 get { return dbType; }
203 [DataCategory ("Data")]
204 #if ONLY_1_0 || ONLY_1_1
205 [DataSysDescription ("Input, output, or bidirectional parameter.")]
206 [DefaultValue (ParameterDirection.Input)]
209 [RefreshProperties (RefreshProperties.All)]
215 ParameterDirection Direction {
216 get { return direction; }
219 switch( direction ) {
220 case ParameterDirection.Output:
221 MetaParameter.Direction = TdsParameterDirection.Output;
223 case ParameterDirection.InputOutput:
224 MetaParameter.Direction = TdsParameterDirection.InputOutput;
226 case ParameterDirection.ReturnValue:
227 MetaParameter.Direction = TdsParameterDirection.ReturnValue;
233 internal TdsMetaParameter MetaParameter {
234 get { return metaParameter; }
237 string IDataParameter.ParameterName {
238 get { return metaParameter.ParameterName; }
239 set { metaParameter.ParameterName = value; }
242 #if ONLY_1_0 || ONLY_1_1
244 [DataSysDescription ("a design-time property used for strongly typed code-generation.")]
245 [DefaultValue (false)]
247 [EditorBrowsable (EditorBrowsableState.Advanced)]
254 get { return metaParameter.IsNullable; }
255 set { metaParameter.IsNullable = value; }
259 [DataCategory ("Data")]
260 #if ONLY_1_0 || ONLY_1_1
261 [DataSysDescription ("Offset in variable length data types.")]
265 [EditorBrowsable (EditorBrowsableState.Advanced)]
272 get { return offset; }
273 set { offset = value; }
276 #if ONLY_1_0 || ONLY_1_1
277 [DataSysDescription ("Name of the parameter, like '@p1'")]
284 string ParameterName {
285 get { return metaParameter.ParameterName; }
286 set { metaParameter.ParameterName = value; }
289 [DataCategory ("Data")]
290 #if ONLY_1_0 || ONLY_1_1
291 [DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
296 [EditorBrowsable (EditorBrowsableState.Never)]
303 get { return metaParameter.Precision; }
304 set { metaParameter.Precision = value; }
307 [DataCategory ("Data")]
308 #if ONLY_1_0 || ONLY_1_1
309 [DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
314 [EditorBrowsable (EditorBrowsableState.Never)]
321 get { return metaParameter.Scale; }
322 set { metaParameter.Scale = value; }
325 [DataCategory ("Data")]
326 #if ONLY_1_0 || ONLY_1_1
327 [DataSysDescription ("Size of variable length data types (string & arrays).")]
335 get { return metaParameter.Size; }
336 set { metaParameter.Size = value; }
339 [DataCategory ("Data")]
340 #if ONLY_1_0 || ONLY_1_1
341 [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.")]
348 string SourceColumn {
349 get { return sourceColumn; }
350 set { sourceColumn = value; }
353 [DataCategory ("Data")]
354 #if ONLY_1_0 || ONLY_1_1
355 [DataSysDescription ("When used by a DataAdapter.Update (UpdateCommand only), the version of the DataRow value that is used to update the data source.")]
356 [DefaultValue (DataRowVersion.Current)]
362 DataRowVersion SourceVersion {
363 get { return sourceVersion; }
364 set { sourceVersion = value; }
367 [DataCategory ("Data")]
368 #if ONLY_1_0 || ONLY_1_1
369 [DataSysDescription ("The parameter native type.")]
370 [DefaultValue (SqlDbType.NVarChar)]
372 [RefreshProperties (RefreshProperties.All)]
374 [DbProviderSpecificTypeProperty(true)]
376 public SqlDbType SqlDbType {
377 get { return sqlDbType; }
379 SetSqlDbType (value);
384 [DataCategory ("Data")]
385 #if ONLY_1_0 || ONLY_1_1
386 [DataSysDescription ("Value of the parameter.")]
387 [DefaultValue (null)]
389 [TypeConverterAttribute (typeof (StringConverter))]
391 [RefreshProperties (RefreshProperties.All)]
398 get { return metaParameter.Value; }
401 InferSqlType (value);
402 metaParameter.Value = SqlTypeToFrameworkType (value);
407 // public SqlCompareOptions CompareInfo{
411 public override bool SourceColumnNullMapping {
412 get { return false ; }
417 #endregion // Properties
421 object ICloneable.Clone ()
423 return new SqlParameter (ParameterName, SqlDbType, Size, Direction, IsNullable, Precision, Scale, SourceColumn, SourceVersion, Value);
426 // If the value is set without the DbType/SqlDbType being set, then we
427 // infer type information.
428 private void InferSqlType (object value)
430 Type type = value.GetType ();
432 string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
434 switch (type.FullName) {
436 case "System.Data.SqlTypes.SqlInt64":
437 SetSqlDbType (SqlDbType.BigInt);
439 case "System.Boolean":
440 case "System.Data.SqlTypes.SqlBoolean":
441 SetSqlDbType (SqlDbType.Bit);
443 case "System.String":
444 case "System.Data.SqlTypes.SqlString":
445 SetSqlDbType (SqlDbType.NVarChar);
447 case "System.DateTime":
448 case "System.Data.SqlTypes.SqlDateTime":
449 SetSqlDbType (SqlDbType.DateTime);
451 case "System.Decimal":
452 case "System.Data.SqlTypes.SqlDecimal":
453 SetSqlDbType (SqlDbType.Decimal);
455 case "System.Double":
456 case "System.Data.SqlTypes.SqlDouble":
457 SetSqlDbType (SqlDbType.Float);
459 case "System.Byte[]":
460 case "System.Data.SqlTypes.SqlBinary":
461 SetSqlDbType (SqlDbType.VarBinary);
464 case "System.Data.SqlTypes.SqlByte":
465 SetSqlDbType (SqlDbType.TinyInt);
468 case "System.Data.SqlTypes.SqlInt32":
469 SetSqlDbType (SqlDbType.Int);
471 case "System.Single":
472 case "System.Data.SqlTypes.Single":
473 SetSqlDbType (SqlDbType.Real);
476 case "System.Data.SqlTypes.SqlInt16":
477 SetSqlDbType (SqlDbType.SmallInt);
480 case "System.Data.SqlTypes.SqlGuid":
481 SetSqlDbType (SqlDbType.UniqueIdentifier);
484 case "System.SmallMoney":
485 case "System.Data.SqlTypes.SqlMoney":
486 SetSqlDbType (SqlDbType.Money);
488 case "System.Object":
489 case "System.DBNull":
490 SetSqlDbType (SqlDbType.Variant); // variant can contain numeric,
491 //string,binary or data and also nul //values, so we can later resolve // it to correct type.
494 throw new ArgumentException (exception);
498 // When the DbType is set, we also set the SqlDbType, as well as the SQL Server
499 // string representation of the type name. If the DbType is not convertible
500 // to an SqlDbType, throw an exception.
501 private void SetDbType (DbType type)
503 string exception = String.Format ("No mapping exists from DbType {0} to a known SqlDbType.", type);
506 case DbType.AnsiString:
507 MetaParameter.TypeName = "varchar";
508 sqlDbType = SqlDbType.VarChar;
509 isVariableSizeType = true;
511 case DbType.AnsiStringFixedLength:
512 MetaParameter.TypeName = "char";
513 sqlDbType = SqlDbType.Char;
514 isVariableSizeType = true;
517 MetaParameter.TypeName = "varbinary";
518 sqlDbType = SqlDbType.VarBinary;
519 isVariableSizeType = true;
522 MetaParameter.TypeName = "bit";
523 sqlDbType = SqlDbType.Bit;
526 MetaParameter.TypeName = "tinyint";
527 sqlDbType = SqlDbType.TinyInt;
529 case DbType.Currency:
530 sqlDbType = SqlDbType.Money;
531 MetaParameter.TypeName = "money";
534 case DbType.DateTime:
535 MetaParameter.TypeName = "datetime";
536 sqlDbType = SqlDbType.DateTime;
539 MetaParameter.TypeName = "decimal";
540 sqlDbType = SqlDbType.Decimal;
543 MetaParameter.TypeName = "float";
544 sqlDbType = SqlDbType.Float;
547 MetaParameter.TypeName = "uniqueidentifier";
548 sqlDbType = SqlDbType.UniqueIdentifier;
551 MetaParameter.TypeName = "smallint";
552 sqlDbType = SqlDbType.SmallInt;
555 MetaParameter.TypeName = "int";
556 sqlDbType = SqlDbType.Int;
559 MetaParameter.TypeName = "bigint";
560 sqlDbType = SqlDbType.BigInt;
563 MetaParameter.TypeName = "sql_variant";
564 sqlDbType = SqlDbType.Variant;
567 MetaParameter.TypeName = "real";
568 sqlDbType = SqlDbType.Real;
571 MetaParameter.TypeName = "nvarchar";
572 sqlDbType = SqlDbType.NVarChar;
573 isVariableSizeType = true;
575 case DbType.StringFixedLength:
576 MetaParameter.TypeName = "nchar";
577 sqlDbType = SqlDbType.NChar;
578 isVariableSizeType = true;
581 MetaParameter.TypeName = "datetime";
582 sqlDbType = SqlDbType.DateTime;
585 throw new ArgumentException (exception);
590 // Used by internal constructor which has a SQL Server typename
591 private void SetDbTypeName (string dbTypeName)
593 switch (dbTypeName.ToLower ()) {
595 SqlDbType = SqlDbType.BigInt;
598 SqlDbType = SqlDbType.Binary;
601 SqlDbType = SqlDbType.Bit;
604 SqlDbType = SqlDbType.Char;
607 SqlDbType = SqlDbType.DateTime;
610 SqlDbType = SqlDbType.Decimal;
613 SqlDbType = SqlDbType.Float;
616 SqlDbType = SqlDbType.Image;
619 SqlDbType = SqlDbType.Int;
622 SqlDbType = SqlDbType.Money;
625 SqlDbType = SqlDbType.NChar;
628 SqlDbType = SqlDbType.NText;
631 SqlDbType = SqlDbType.NVarChar;
634 SqlDbType = SqlDbType.Real;
636 case "smalldatetime":
637 SqlDbType = SqlDbType.SmallDateTime;
640 SqlDbType = SqlDbType.SmallInt;
643 SqlDbType = SqlDbType.SmallMoney;
646 SqlDbType = SqlDbType.Text;
649 SqlDbType = SqlDbType.Timestamp;
652 SqlDbType = SqlDbType.TinyInt;
654 case "uniqueidentifier":
655 SqlDbType = SqlDbType.UniqueIdentifier;
658 SqlDbType = SqlDbType.VarBinary;
661 SqlDbType = SqlDbType.VarChar;
664 SqlDbType = SqlDbType.Variant;
669 // When the SqlDbType is set, we also set the DbType, as well as the SQL Server
670 // string representation of the type name. If the SqlDbType is not convertible
671 // to a DbType, throw an exception.
672 private void SetSqlDbType (SqlDbType type)
674 string exception = String.Format ("No mapping exists from SqlDbType {0} to a known DbType.", type);
677 case SqlDbType.BigInt:
678 MetaParameter.TypeName = "bigint";
679 dbType = DbType.Int64;
681 case SqlDbType.Binary:
682 MetaParameter.TypeName = "binary";
683 dbType = DbType.Binary;
684 isVariableSizeType = true;
686 case SqlDbType.Timestamp:
687 MetaParameter.TypeName = "timestamp";
688 dbType = DbType.Binary;
690 case SqlDbType.VarBinary:
691 MetaParameter.TypeName = "varbinary";
692 dbType = DbType.Binary;
693 isVariableSizeType = true;
696 MetaParameter.TypeName = "bit";
697 dbType = DbType.Boolean;
700 MetaParameter.TypeName = "char";
701 dbType = DbType.AnsiStringFixedLength;
702 isVariableSizeType = true;
704 case SqlDbType.DateTime:
705 MetaParameter.TypeName = "datetime";
706 dbType = DbType.DateTime;
708 case SqlDbType.SmallDateTime:
709 MetaParameter.TypeName = "smalldatetime";
710 dbType = DbType.DateTime;
712 case SqlDbType.Decimal:
713 MetaParameter.TypeName = "decimal";
714 dbType = DbType.Decimal;
716 case SqlDbType.Float:
717 MetaParameter.TypeName = "float";
718 dbType = DbType.Double;
720 case SqlDbType.Image:
721 MetaParameter.TypeName = "image";
722 dbType = DbType.Binary;
723 isVariableSizeType = true;
726 MetaParameter.TypeName = "int";
727 dbType = DbType.Int32;
729 case SqlDbType.Money:
730 MetaParameter.TypeName = "money";
731 dbType = DbType.Currency;
733 case SqlDbType.SmallMoney:
734 MetaParameter.TypeName = "smallmoney";
735 dbType = DbType.Currency;
737 case SqlDbType.NChar:
738 MetaParameter.TypeName = "nchar";
739 dbType = DbType.StringFixedLength;
740 isVariableSizeType = true;
742 case SqlDbType.NText:
743 MetaParameter.TypeName = "ntext";
744 dbType = DbType.String;
745 isVariableSizeType = true;
747 case SqlDbType.NVarChar:
748 MetaParameter.TypeName = "nvarchar";
749 dbType = DbType.String;
750 isVariableSizeType = true;
753 MetaParameter.TypeName = "real";
754 dbType = DbType.Single;
756 case SqlDbType.SmallInt:
757 MetaParameter.TypeName = "smallint";
758 dbType = DbType.Int16;
761 MetaParameter.TypeName = "text";
762 dbType = DbType.AnsiString;
763 isVariableSizeType = true;
765 case SqlDbType.VarChar:
766 MetaParameter.TypeName = "varchar";
767 dbType = DbType.AnsiString;
768 isVariableSizeType = true;
770 case SqlDbType.TinyInt:
771 MetaParameter.TypeName = "tinyint";
772 dbType = DbType.Byte;
774 case SqlDbType.UniqueIdentifier:
775 MetaParameter.TypeName = "uniqueidentifier";
776 dbType = DbType.Guid;
778 case SqlDbType.Variant:
779 MetaParameter.TypeName = "sql_variant";
780 dbType = DbType.Object;
783 throw new ArgumentException (exception);
788 public override string ToString()
790 return ParameterName;
793 private object SqlTypeToFrameworkType (object value)
795 if (! (value is INullable)) // if the value is not SqlType
798 // Map to .net type, as Mono TDS respects only types from .net
799 switch (value.GetType ().FullName) {
800 case "System.Data.SqlTypes.SqlBinary":
801 return ( (SqlBinary) value).Value;
802 case "System.Data.SqlTypes.SqlBoolean":
803 return ( (SqlBoolean) value).Value;
804 case "System.Data.SqlTypes.SqlByte":
805 return ( (SqlByte) value).Value;
806 case "System.Data.SqlTypes.SqlDateTime":
807 return ( (SqlDateTime) value).Value;
808 case "System.Data.SqlTypes.SqlDecimal":
809 return ( (SqlDecimal) value).Value;
810 case "System.Data.SqlTypes.SqlDouble":
811 return ( (SqlDouble) value).Value;
812 case "System.Data.SqlTypes.SqlGuid":
813 return ( (SqlGuid) value).Value;
814 case "System.Data.SqlTypes.SqlInt16":
815 return ( (SqlInt16) value).Value;
816 case "System.Data.SqlTypes.SqlInt32 ":
817 return ( (SqlInt32 ) value).Value;
818 case "System.Data.SqlTypes.SqlInt64":
819 return ( (SqlInt64) value).Value;
820 case "System.Data.SqlTypes.SqlMoney":
821 return ( (SqlMoney) value).Value;
822 case "System.Data.SqlTypes.SqlSingle":
823 return ( (SqlSingle) value).Value;
824 case "System.Data.SqlTypes.SqlString":
825 return ( (SqlString) value).Value;
832 public override void CopyTo (DbParameter param)
834 throw new NotImplementedException ();
838 public override void ResetDbType ()
840 throw new NotImplementedException ();
844 #endregion // Methods