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 isSizeSet = 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)
83 public SqlParameter (string parameterName, object value)
85 metaParameter = new TdsMetaParameter (parameterName, SqlTypeToFrameworkType (value));
86 this.sourceVersion = DataRowVersion.Current;
90 public SqlParameter (string parameterName, SqlDbType dbType)
91 : this (parameterName, dbType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
95 public SqlParameter (string parameterName, SqlDbType dbType, int size)
96 : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
100 public SqlParameter (string parameterName, SqlDbType dbType, int size, string sourceColumn)
101 : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, sourceColumn, DataRowVersion.Current, null)
105 [EditorBrowsable (EditorBrowsableState.Advanced)]
106 public SqlParameter (string parameterName, SqlDbType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value)
108 metaParameter = new TdsMetaParameter (parameterName, size,
109 isNullable, precision,
111 SqlTypeToFrameworkType (value));
113 Direction = direction;
114 SourceColumn = sourceColumn;
115 SourceVersion = sourceVersion;
118 // This constructor is used internally to construct a
119 // SqlParameter. The value array comes from sp_procedure_params_rowset.
120 // This is in SqlCommand.DeriveParameters.
121 internal SqlParameter (object[] dbValues)
122 : this (dbValues [3].ToString (), String.Empty)
126 Direction = ParameterDirection.Input;
128 ParameterName = (string) dbValues[3];
130 switch ((short) dbValues[5]) {
132 Direction = ParameterDirection.Input;
135 Direction = ParameterDirection.Output;
138 Direction = ParameterDirection.InputOutput;
141 Direction = ParameterDirection.ReturnValue;
144 Direction = ParameterDirection.Input;
147 IsNullable = (dbValues [8] != null &&
148 dbValues [8] != DBNull.Value) ? (bool) dbValues [8] : false;
150 if (dbValues [12] != null && dbValues [12] != DBNull.Value)
151 Precision = (byte) ((short) dbValues [12]);
153 if (dbValues [13] != null && dbValues [13] != DBNull.Value)
154 Scale = (byte) ( (short) dbValues [13]);
156 SetDbTypeName ((string) dbValues [16]);
159 #endregion // Constructors
163 // Used to ensure that only one collection can contain this
165 internal SqlParameterCollection Container {
166 get { return container; }
167 set { container = value; }
170 #if ONLY_1_0 || ONLY_1_1
172 [DataSysDescription ("The parameter generic type.")]
173 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
174 [RefreshProperties (RefreshProperties.All)]
176 [DataCategory ("Data")]
182 get { return dbType; }
189 [DataCategory ("Data")]
190 #if ONLY_1_0 || ONLY_1_1
191 [DataSysDescription ("Input, output, or bidirectional parameter.")]
192 [DefaultValue (ParameterDirection.Input)]
195 [RefreshProperties (RefreshProperties.All)]
201 ParameterDirection Direction {
202 get { return direction; }
205 switch( direction ) {
206 case ParameterDirection.Output:
207 MetaParameter.Direction = TdsParameterDirection.Output;
209 case ParameterDirection.InputOutput:
210 MetaParameter.Direction = TdsParameterDirection.InputOutput;
212 case ParameterDirection.ReturnValue:
213 MetaParameter.Direction = TdsParameterDirection.ReturnValue;
219 internal TdsMetaParameter MetaParameter {
220 get { return metaParameter; }
223 string IDataParameter.ParameterName {
224 get { return metaParameter.ParameterName; }
225 set { metaParameter.ParameterName = value; }
228 #if ONLY_1_0 || ONLY_1_1
230 [DataSysDescription ("a design-time property used for strongly typed code-generation.")]
231 [DefaultValue (false)]
233 [EditorBrowsable (EditorBrowsableState.Advanced)]
240 get { return metaParameter.IsNullable; }
241 set { metaParameter.IsNullable = value; }
245 [DataCategory ("Data")]
246 #if ONLY_1_0 || ONLY_1_1
247 [DataSysDescription ("Offset in variable length data types.")]
251 [EditorBrowsable (EditorBrowsableState.Advanced)]
258 get { return offset; }
259 set { offset = value; }
262 #if ONLY_1_0 || ONLY_1_1
263 [DataSysDescription ("Name of the parameter, like '@p1'")]
270 string ParameterName {
271 get { return metaParameter.ParameterName; }
272 set { metaParameter.ParameterName = value; }
275 [DataCategory ("Data")]
276 #if ONLY_1_0 || ONLY_1_1
277 [DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
282 [EditorBrowsable (EditorBrowsableState.Never)]
289 get { return metaParameter.Precision; }
290 set { metaParameter.Precision = value; }
293 [DataCategory ("Data")]
294 #if ONLY_1_0 || ONLY_1_1
295 [DataSysDescription ("For decimal, numeric, varnumeric DBTypes.")]
300 [EditorBrowsable (EditorBrowsableState.Never)]
307 get { return metaParameter.Scale; }
308 set { metaParameter.Scale = value; }
311 [DataCategory ("Data")]
312 #if ONLY_1_0 || ONLY_1_1
313 [DataSysDescription ("Size of variable length data types (strings & arrays).")]
321 get { return metaParameter.Size; }
322 set { metaParameter.Size = value; }
325 [DataCategory ("Data")]
326 #if ONLY_1_0 || ONLY_1_1
327 [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.")]
334 string SourceColumn {
335 get { return sourceColumn; }
336 set { sourceColumn = value; }
339 [DataCategory ("Data")]
340 #if ONLY_1_0 || ONLY_1_1
341 [DataSysDescription ("When used by a DataAdapter.Update (UpdateCommand only), the version of the DataRow value that is used to update the data source.")]
342 [DefaultValue (DataRowVersion.Current)]
348 DataRowVersion SourceVersion {
349 get { return sourceVersion; }
350 set { sourceVersion = value; }
353 [DataCategory ("Data")]
354 #if ONLY_1_0 || ONLY_1_1
355 [DataSysDescription ("The parameter native type.")]
356 [DefaultValue (SqlDbType.NVarChar)]
358 [RefreshProperties (RefreshProperties.All)]
360 [DbProviderSpecificTypeProperty(true)]
362 public SqlDbType SqlDbType {
363 get { return sqlDbType; }
365 SetSqlDbType (value);
370 [DataCategory ("Data")]
371 #if ONLY_1_0 || ONLY_1_1
372 [DataSysDescription ("Value of the parameter.")]
373 [DefaultValue (null)]
375 [TypeConverterAttribute (typeof (StringConverter))]
377 [RefreshProperties (RefreshProperties.All)]
384 get { return metaParameter.Value; }
387 InferSqlType (value);
388 metaParameter.Value = SqlTypeToFrameworkType (value);
393 // public SqlCompareOptions CompareInfo{
397 #endregion // Properties
401 object ICloneable.Clone ()
403 return new SqlParameter (ParameterName, SqlDbType, Size, Direction, IsNullable, Precision, Scale, SourceColumn, SourceVersion, Value);
406 // If the value is set without the DbType/SqlDbType being set, then we
407 // infer type information.
408 private void InferSqlType (object value)
410 Type type = value.GetType ();
412 string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
414 switch (type.FullName) {
416 case "System.Data.SqlTypes.SqlInt64":
417 SetSqlDbType (SqlDbType.BigInt);
419 case "System.Boolean":
420 case "System.Data.SqlTypes.SqlBoolean":
421 SetSqlDbType (SqlDbType.Bit);
423 case "System.String":
424 case "System.Data.SqlTypes.SqlString":
425 SetSqlDbType (SqlDbType.NVarChar);
427 case "System.DateTime":
428 case "System.Data.SqlTypes.SqlDateTime":
429 SetSqlDbType (SqlDbType.DateTime);
431 case "System.Decimal":
432 case "System.Data.SqlTypes.SqlDecimal":
433 SetSqlDbType (SqlDbType.Decimal);
435 case "System.Double":
436 case "System.Data.SqlTypes.SqlDouble":
437 SetSqlDbType (SqlDbType.Float);
439 case "System.Byte[]":
440 case "System.Data.SqlTypes.SqlBinary":
441 SetSqlDbType (SqlDbType.VarBinary);
444 case "System.Data.SqlTypes.SqlByte":
445 SetSqlDbType (SqlDbType.TinyInt);
448 case "System.Data.SqlTypes.SqlInt32":
449 SetSqlDbType (SqlDbType.Int);
451 case "System.Single":
452 case "System.Data.SqlTypes.Single":
453 SetSqlDbType (SqlDbType.Real);
456 case "System.Data.SqlTypes.SqlInt16":
457 SetSqlDbType (SqlDbType.SmallInt);
460 case "System.Data.SqlTypes.SqlGuid":
461 SetSqlDbType (SqlDbType.UniqueIdentifier);
464 case "System.SmallMoney":
465 case "System.Data.SqlTypes.SqlMoney":
466 SetSqlDbType (SqlDbType.Money);
468 case "System.Object":
469 case "System.DBNull":
470 SetSqlDbType (SqlDbType.Variant); // variant can contain numeric,
471 //string,binary or data and also nul //values, so we can later resolve // it to correct type.
474 throw new ArgumentException (exception);
478 // When the DbType is set, we also set the SqlDbType, as well as the SQL Server
479 // string representation of the type name. If the DbType is not convertible
480 // to an SqlDbType, throw an exception.
481 private void SetDbType (DbType type)
483 string exception = String.Format ("No mapping exists from DbType {0} to a known SqlDbType.", type);
486 case DbType.AnsiString:
487 MetaParameter.TypeName = "varchar";
488 sqlDbType = SqlDbType.VarChar;
490 case DbType.AnsiStringFixedLength:
491 MetaParameter.TypeName = "char";
492 sqlDbType = SqlDbType.Char;
495 MetaParameter.TypeName = "varbinary";
496 sqlDbType = SqlDbType.VarBinary;
499 MetaParameter.TypeName = "bit";
500 sqlDbType = SqlDbType.Bit;
503 MetaParameter.TypeName = "tinyint";
504 sqlDbType = SqlDbType.TinyInt;
506 case DbType.Currency:
507 sqlDbType = SqlDbType.Money;
508 MetaParameter.TypeName = "money";
511 case DbType.DateTime:
512 MetaParameter.TypeName = "datetime";
513 sqlDbType = SqlDbType.DateTime;
516 MetaParameter.TypeName = "decimal";
517 sqlDbType = SqlDbType.Decimal;
520 MetaParameter.TypeName = "float";
521 sqlDbType = SqlDbType.Float;
524 MetaParameter.TypeName = "uniqueidentifier";
525 sqlDbType = SqlDbType.UniqueIdentifier;
528 MetaParameter.TypeName = "smallint";
529 sqlDbType = SqlDbType.SmallInt;
532 MetaParameter.TypeName = "int";
533 sqlDbType = SqlDbType.Int;
536 MetaParameter.TypeName = "bigint";
537 sqlDbType = SqlDbType.BigInt;
540 MetaParameter.TypeName = "sql_variant";
541 sqlDbType = SqlDbType.Variant;
544 MetaParameter.TypeName = "real";
545 sqlDbType = SqlDbType.Real;
548 MetaParameter.TypeName = "nvarchar";
549 sqlDbType = SqlDbType.NVarChar;
551 case DbType.StringFixedLength:
552 MetaParameter.TypeName = "nchar";
553 sqlDbType = SqlDbType.NChar;
556 MetaParameter.TypeName = "datetime";
557 sqlDbType = SqlDbType.DateTime;
560 throw new ArgumentException (exception);
565 // Used by internal constructor which has a SQL Server typename
566 private void SetDbTypeName (string dbTypeName)
568 switch (dbTypeName.ToLower ()) {
570 SqlDbType = SqlDbType.BigInt;
573 SqlDbType = SqlDbType.Binary;
576 SqlDbType = SqlDbType.Bit;
579 SqlDbType = SqlDbType.Char;
582 SqlDbType = SqlDbType.DateTime;
585 SqlDbType = SqlDbType.Decimal;
588 SqlDbType = SqlDbType.Float;
591 SqlDbType = SqlDbType.Image;
594 SqlDbType = SqlDbType.Int;
597 SqlDbType = SqlDbType.Money;
600 SqlDbType = SqlDbType.NChar;
603 SqlDbType = SqlDbType.NText;
606 SqlDbType = SqlDbType.NVarChar;
609 SqlDbType = SqlDbType.Real;
611 case "smalldatetime":
612 SqlDbType = SqlDbType.SmallDateTime;
615 SqlDbType = SqlDbType.SmallInt;
618 SqlDbType = SqlDbType.SmallMoney;
621 SqlDbType = SqlDbType.Text;
624 SqlDbType = SqlDbType.Timestamp;
627 SqlDbType = SqlDbType.TinyInt;
629 case "uniqueidentifier":
630 SqlDbType = SqlDbType.UniqueIdentifier;
633 SqlDbType = SqlDbType.VarBinary;
636 SqlDbType = SqlDbType.VarChar;
639 SqlDbType = SqlDbType.Variant;
644 // When the SqlDbType is set, we also set the DbType, as well as the SQL Server
645 // string representation of the type name. If the SqlDbType is not convertible
646 // to a DbType, throw an exception.
647 private void SetSqlDbType (SqlDbType type)
649 string exception = String.Format ("No mapping exists from SqlDbType {0} to a known DbType.", type);
652 case SqlDbType.BigInt:
653 MetaParameter.TypeName = "bigint";
654 dbType = DbType.Int64;
656 case SqlDbType.Binary:
657 MetaParameter.TypeName = "binary";
658 dbType = DbType.Binary;
660 case SqlDbType.Timestamp:
661 MetaParameter.TypeName = "timestamp";
662 dbType = DbType.Binary;
664 case SqlDbType.VarBinary:
665 MetaParameter.TypeName = "varbinary";
666 dbType = DbType.Binary;
669 MetaParameter.TypeName = "bit";
670 dbType = DbType.Boolean;
673 MetaParameter.TypeName = "char";
674 dbType = DbType.AnsiStringFixedLength;
676 case SqlDbType.DateTime:
677 MetaParameter.TypeName = "datetime";
678 dbType = DbType.DateTime;
680 case SqlDbType.SmallDateTime:
681 MetaParameter.TypeName = "smalldatetime";
682 dbType = DbType.DateTime;
684 case SqlDbType.Decimal:
685 MetaParameter.TypeName = "decimal";
686 dbType = DbType.Decimal;
688 case SqlDbType.Float:
689 MetaParameter.TypeName = "float";
690 dbType = DbType.Double;
692 case SqlDbType.Image:
693 MetaParameter.TypeName = "image";
694 dbType = DbType.Binary;
697 MetaParameter.TypeName = "int";
698 dbType = DbType.Int32;
700 case SqlDbType.Money:
701 MetaParameter.TypeName = "money";
702 dbType = DbType.Currency;
704 case SqlDbType.SmallMoney:
705 MetaParameter.TypeName = "smallmoney";
706 dbType = DbType.Currency;
708 case SqlDbType.NChar:
709 MetaParameter.TypeName = "nchar";
710 dbType = DbType.StringFixedLength;
712 case SqlDbType.NText:
713 MetaParameter.TypeName = "ntext";
714 dbType = DbType.String;
716 case SqlDbType.NVarChar:
717 MetaParameter.TypeName = "nvarchar";
718 dbType = DbType.String;
721 MetaParameter.TypeName = "real";
722 dbType = DbType.Single;
724 case SqlDbType.SmallInt:
725 MetaParameter.TypeName = "smallint";
726 dbType = DbType.Int16;
729 MetaParameter.TypeName = "text";
730 dbType = DbType.AnsiString;
732 case SqlDbType.VarChar:
733 MetaParameter.TypeName = "varchar";
734 dbType = DbType.AnsiString;
736 case SqlDbType.TinyInt:
737 MetaParameter.TypeName = "tinyint";
738 dbType = DbType.Byte;
740 case SqlDbType.UniqueIdentifier:
741 MetaParameter.TypeName = "uniqueidentifier";
742 dbType = DbType.Guid;
744 case SqlDbType.Variant:
745 MetaParameter.TypeName = "sql_variant";
746 dbType = DbType.Object;
749 throw new ArgumentException (exception);
754 public override string ToString()
756 return ParameterName;
759 private object SqlTypeToFrameworkType (object value)
761 if (! (value is INullable)) // if the value is not SqlType
764 // Map to .net type, as Mono TDS respects only types from .net
765 switch (value.GetType ().FullName) {
766 case "System.Data.SqlTypes.SqlBinary":
767 return ( (SqlBinary) value).Value;
768 case "System.Data.SqlTypes.SqlBoolean":
769 return ( (SqlBoolean) value).Value;
770 case "System.Data.SqlTypes.SqlByte":
771 return ( (SqlByte) value).Value;
772 case "System.Data.SqlTypes.SqlDateTime":
773 return ( (SqlDateTime) value).Value;
774 case "System.Data.SqlTypes.SqlDecimal":
775 return ( (SqlDecimal) value).Value;
776 case "System.Data.SqlTypes.SqlDouble":
777 return ( (SqlDouble) value).Value;
778 case "System.Data.SqlTypes.SqlGuid":
779 return ( (SqlGuid) value).Value;
780 case "System.Data.SqlTypes.SqlInt16":
781 return ( (SqlInt16) value).Value;
782 case "System.Data.SqlTypes.SqlInt32 ":
783 return ( (SqlInt32 ) value).Value;
784 case "System.Data.SqlTypes.SqlInt64":
785 return ( (SqlInt64) value).Value;
786 case "System.Data.SqlTypes.SqlMoney":
787 return ( (SqlMoney) value).Value;
788 case "System.Data.SqlTypes.SqlSingle":
789 return ( (SqlSingle) value).Value;
790 case "System.Data.SqlTypes.SqlString":
791 return ( (SqlString) value).Value;
798 public override void CopyTo (DbParameter param)
800 throw new NotImplementedException ();
804 public override void ResetDbType ()
806 throw new NotImplementedException ();
810 #endregion // Methods