2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Mono.Data.SybaseClient / Mono.Data.SybaseClient / SybaseParameter.cs
index 4cc458bd964686acd1b7a017fad93862a425d69e..431dfaf6f9c3e9907348af1c86be1768e8b88ada 100644 (file)
@@ -2,11 +2,37 @@
 // Mono.Data.SybaseClient.SybaseParameter.cs
 //
 // Author:
+//   Rodrigo Moya (rodrigo@ximian.com)
+//   Daniel Morgan (danmorg@sc.rr.com)
 //   Tim Coleman (tim@timcoleman.com)
 //
+// (C) Ximian, Inc. 2002
 // Copyright (C) Tim Coleman, 2002
 //
 
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using Mono.Data.Tds;
+using Mono.Data.Tds.Protocol;
 using System;
 using System.ComponentModel;
 using System.Data;
@@ -19,209 +45,532 @@ namespace Mono.Data.SybaseClient {
        {
                #region Fields
 
-               string parmName;
-               SybaseType dbtype;
-               DbType theDbType;
-               object objValue;
-               int size;
-               string sourceColumn;
+               TdsMetaParameter metaParameter;
+
+               SybaseParameterCollection container = null;
+               DbType dbType;
                ParameterDirection direction = ParameterDirection.Input;
                bool isNullable;
-               byte precision;
-               byte scale;
-               DataRowVersion sourceVersion;
+               bool isSizeSet = false;
+               bool isTypeSet = false;
                int offset;
-
-               bool sizeSet = false;
+               SybaseType sybaseType;
+               string sourceColumn;
+               DataRowVersion sourceVersion;
 
                #endregion // Fields
 
                #region Constructors
 
-               [MonoTODO]
                public SybaseParameter () 
+                       : this (String.Empty, SybaseType.NVarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
                {
                }
 
-               [MonoTODO]
                public SybaseParameter (string parameterName, object value) 
                {
-                       this.parmName = parameterName;
-                       this.objValue = value;
+                       metaParameter = new TdsMetaParameter (parameterName, value);
+                       this.sourceVersion = DataRowVersion.Current;
+                       InferSybaseType (value);
                }
                
-               [MonoTODO]
                public SybaseParameter (string parameterName, SybaseType dbType) 
+                       : this (parameterName, dbType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
                {
-                       this.parmName = parameterName;
-                       this.dbtype = dbType;
                }
 
-               [MonoTODO]
                public SybaseParameter (string parameterName, SybaseType dbType, int size) 
+                       : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
                {
-
-                       this.parmName = parameterName;
-                       this.dbtype = dbType;
-                       this.size = size;
                }
                
-               [MonoTODO]
-               public SybaseParameter(string parameterName, SybaseType dbType, int size, string sourceColumn) 
+               public SybaseParameter (string parameterName, SybaseType dbType, int size, string sourceColumn) 
+                       : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, sourceColumn, DataRowVersion.Current, null)
                {
+               }
+               
+               [EditorBrowsable (EditorBrowsableState.Advanced)]        
+               public SybaseParameter (string parameterName, SybaseType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value) 
+               {
+                       metaParameter = new TdsMetaParameter (parameterName, size, isNullable, precision, scale, value);
 
-                       this.parmName = parameterName;
-                       this.dbtype = dbType;
-                       this.size = size;
-                       this.sourceColumn = sourceColumn;
+                       SybaseType = dbType;
+                       Direction = direction;
+                       SourceColumn = sourceColumn;
+                       SourceVersion = sourceVersion;
                }
-                        
-               [MonoTODO]
-               public SybaseParameter(string parameterName, SybaseType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value) 
+
+               // This constructor is used internally to construct a
+               // SybaseParameter.  The value array comes from sp_procedure_params_rowset.
+               // This is in SybaseCommand.DeriveParameters.
+               internal SybaseParameter (object[] dbValues)
                {
-                       
-                       this.parmName = parameterName;
-                       this.dbtype = dbType;
-                       this.size = size;
-                       this.sourceColumn = sourceColumn;
-                       this.direction = direction;
-                       this.isNullable = isNullable;
-                       this.precision = precision;
-                       this.scale = scale;
-                       this.sourceVersion = sourceVersion;
-                       this.objValue = value;
+                       Precision = 0;
+                       Scale = 0;
+                       Direction = ParameterDirection.Input;
+
+                       ParameterName = (string) dbValues[3];
+
+                       switch ((short) dbValues[5]) {
+                       case 1:
+                               Direction = ParameterDirection.Input;
+                               break;
+                       case 2:
+                               Direction = ParameterDirection.Output;
+                               break;
+                       case 3:
+                               Direction = ParameterDirection.InputOutput;
+                               break;
+                       case 4:
+                               Direction = ParameterDirection.ReturnValue;
+                               break;
+                       }
+
+                       IsNullable = (bool) dbValues[8];
+
+                       if (dbValues[12] != null)
+                               Precision = (byte) ((short) dbValues[12]);
+                       if (dbValues[13] != null)
+                               Scale = (byte) ((short) dbValues[13]);
+
+                       SetDbTypeName ((string) dbValues[16]);
                }
 
                #endregion // Constructors
 
                #region Properties
 
-               [MonoTODO]
+               // Used to ensure that only one collection can contain this
+               // parameter
+               internal SybaseParameterCollection Container {
+                       get { return container; }
+                       set { container = value; }
+               }
+
                public DbType DbType {
-                       get { return theDbType; }
-                       set { theDbType = value; }
+                       get { return dbType; }
+                       set { 
+                               SetDbType (value); 
+                               isTypeSet = true;
+                       }
                }
 
-               [MonoTODO]
                public ParameterDirection Direction {
                        get { return direction; }
-                       set { direction = value; }
+                       set { 
+                               direction = value; 
+                               if (direction == ParameterDirection.Output)
+                                       MetaParameter.Direction = TdsParameterDirection.Output;
+                       }
+               }
+
+               internal TdsMetaParameter MetaParameter {
+                       get { return metaParameter; }
+               }
+
+               string IDataParameter.ParameterName {
+                       get { return metaParameter.ParameterName; }
+                       set { metaParameter.ParameterName = value; }
                }
 
-               [MonoTODO]
                public bool IsNullable  {
-                       get { return isNullable; }
+                       get { return metaParameter.IsNullable; }
+                       set { metaParameter.IsNullable = value; }
                }
 
-               [MonoTODO]
                public int Offset {
                        get { return offset; }
                        set { offset = value; }
                }
-
-               
-               string IDataParameter.ParameterName {
-                       get { return parmName; }
-                       set { parmName = value; }
-               }
                
                public string ParameterName {
-                       get { return parmName; }
-                       set { parmName = value; }
+                       get { return metaParameter.ParameterName; }
+                       set { metaParameter.ParameterName = value; }
+               }
+
+               public byte Precision {
+                       get { return metaParameter.Precision; }
+                       set { metaParameter.Precision = value; }
+               }
+
+                public byte Scale {
+                       get { return metaParameter.Scale; }
+                       set { metaParameter.Scale = value; }
+               }
+
+                public int Size {
+                       get { return metaParameter.Size; }
+                       set { metaParameter.Size = value; }
                }
 
-               [MonoTODO]
                public string SourceColumn {
                        get { return sourceColumn; }
                        set { sourceColumn = value; }
                }
 
-               [MonoTODO]
                public DataRowVersion SourceVersion {
                        get { return sourceVersion; }
                        set { sourceVersion = value; }
                }
                
-               [MonoTODO]
                public SybaseType SybaseType {
-                       get { return dbtype; }
-                       set { dbtype = value; }
+                       get { return sybaseType; }
+                       set { 
+                               SetSybaseType (value); 
+                               isTypeSet = true;
+                       }
                }
 
-               [MonoTODO]
                public object Value {
-                       get { return objValue; }
-                       set { objValue = value; }
+                       get { return metaParameter.Value; }
+                       set { 
+                               if (!isTypeSet)
+                                       InferSybaseType (value);
+                               metaParameter.Value = value; 
+                       }
                }
 
-               [MonoTODO]
-               public byte Precision {
-                       get { return precision; }
-                       set { precision = value; }
-               }
+               #endregion // Properties
 
-               [MonoTODO]
-                public byte Scale {
-                       get { return scale; }
-                       set { scale = value; }
+               #region Methods
+
+               object ICloneable.Clone ()
+               {
+                       return new SybaseParameter (ParameterName, SybaseType, Size, Direction, IsNullable, Precision, Scale, SourceColumn, SourceVersion, Value);
                }
 
-               [MonoTODO]
-                public int Size {
-                       get { return size; }
-                       set { 
-                               sizeSet = true;
-                               size = value; 
+               // If the value is set without the DbType/SybaseType being set, then we
+               // infer type information.
+               private void InferSybaseType (object value)
+               {
+                       Type type = value.GetType ();
+
+                       string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
+
+                       switch (type.FullName) {
+                       case "System.Int64":
+                               SetSybaseType (SybaseType.BigInt);
+                               break;
+                       case "System.Boolean":
+                               SetSybaseType (SybaseType.Bit);
+                               break;
+                       case "System.String":
+                               SetSybaseType (SybaseType.NVarChar);
+                               break;
+                       case "System.DateTime":
+                               SetSybaseType (SybaseType.DateTime);
+                               break;
+                       case "System.Decimal":
+                               SetSybaseType (SybaseType.Decimal);
+                               break;
+                       case "System.Double":
+                               SetSybaseType (SybaseType.Float);
+                               break;
+                       case "System.Byte[]":
+                               SetSybaseType (SybaseType.VarBinary);
+                               break;
+                       case "System.Byte":
+                               SetSybaseType (SybaseType.TinyInt);
+                               break;
+                       case "System.Int32":
+                               SetSybaseType (SybaseType.Int);
+                               break;
+                       case "System.Single":
+                               SetSybaseType (SybaseType.Real);
+                               break;
+                       case "System.Int16":
+                               SetSybaseType (SybaseType.SmallInt);
+                               break;
+                       case "System.Guid":
+                               SetSybaseType (SybaseType.UniqueIdentifier);
+                               break;
+                       case "System.Object":
+                               SetSybaseType (SybaseType.Variant);
+                               break;
+                       default:
+                               throw new ArgumentException (exception);                                
                        }
                }
 
-               #endregion // Properties
+               // When the DbType is set, we also set the SybaseType, as well as the SQL Server
+               // string representation of the type name.  If the DbType is not convertible
+               // to an SybaseType, throw an exception.
+               private void SetDbType (DbType type)
+               {
+                       string exception = String.Format ("No mapping exists from DbType {0} to a known SybaseType.", type);
 
-               #region Methods
+                       switch (type) {
+                       case DbType.AnsiString:
+                               MetaParameter.TypeName = "varchar";
+                               sybaseType = SybaseType.VarChar;
+                               break;
+                       case DbType.AnsiStringFixedLength:
+                               MetaParameter.TypeName = "char";
+                               sybaseType = SybaseType.Char;
+                               break;
+                       case DbType.Binary:
+                               MetaParameter.TypeName = "varbinary";
+                               sybaseType = SybaseType.VarBinary;
+                               break;
+                       case DbType.Boolean:
+                               MetaParameter.TypeName = "bit";
+                               sybaseType = SybaseType.Bit;
+                               break;
+                       case DbType.Byte:
+                               MetaParameter.TypeName = "tinyint";
+                               sybaseType = SybaseType.TinyInt;
+                               break;
+                       case DbType.Currency:
+                               sybaseType = SybaseType.Money;
+                               MetaParameter.TypeName = "money";
+                               break;
+                       case DbType.Date:
+                       case DbType.DateTime:
+                               MetaParameter.TypeName = "datetime";
+                               sybaseType = SybaseType.DateTime;
+                               break;
+                       case DbType.Decimal:
+                               MetaParameter.TypeName = "decimal";
+                               sybaseType = SybaseType.Decimal;
+                               break;
+                       case DbType.Double:
+                               MetaParameter.TypeName = "float";
+                               sybaseType = SybaseType.Float;
+                               break;
+                       case DbType.Guid:
+                               MetaParameter.TypeName = "uniqueidentifier";
+                               sybaseType = SybaseType.UniqueIdentifier;
+                               break;
+                       case DbType.Int16:
+                               MetaParameter.TypeName = "smallint";
+                               sybaseType = SybaseType.SmallInt;
+                               break;
+                       case DbType.Int32:
+                               MetaParameter.TypeName = "int";
+                               sybaseType = SybaseType.Int;
+                               break;
+                       case DbType.Int64:
+                               MetaParameter.TypeName = "bigint";
+                               sybaseType = SybaseType.BigInt;
+                               break;
+                       case DbType.Object:
+                               MetaParameter.TypeName = "sql_variant";
+                               sybaseType = SybaseType.Variant;
+                               break;
+                       case DbType.Single:
+                               MetaParameter.TypeName = "real";
+                               sybaseType = SybaseType.Real;
+                               break;
+                       case DbType.String:
+                               MetaParameter.TypeName = "nvarchar";
+                               sybaseType = SybaseType.NVarChar;
+                               break;
+                       case DbType.StringFixedLength:
+                               MetaParameter.TypeName = "nchar";
+                               sybaseType = SybaseType.NChar;
+                               break;
+                       case DbType.Time:
+                               MetaParameter.TypeName = "datetime";
+                               sybaseType = SybaseType.DateTime;
+                               break;
+                       default:
+                               throw new ArgumentException (exception);
+                       }
+                       dbType = type;
+               }
 
-               [MonoTODO]
-               object ICloneable.Clone ()
+               // Used by internal constructor which has a SQL Server typename
+               private void SetDbTypeName (string dbTypeName)
                {
-                       throw new NotImplementedException ();
+                       switch (dbTypeName.ToLower ()) {        
+                       case "bigint":
+                               SybaseType = SybaseType.BigInt;
+                               break;
+                       case "binary":
+                               SybaseType = SybaseType.Binary;
+                               break;
+                       case "bit":
+                               SybaseType = SybaseType.Bit;
+                               break;
+                       case "char":
+                               SybaseType = SybaseType.Char;
+                               break;
+                       case "datetime":
+                               SybaseType = SybaseType.DateTime;
+                               break;
+                       case "decimal":
+                               SybaseType = SybaseType.Decimal;
+                               break;
+                       case "float":
+                               SybaseType = SybaseType.Float;
+                               break;
+                       case "image":
+                               SybaseType = SybaseType.Image;
+                               break;
+                       case "int":
+                               SybaseType = SybaseType.Int;
+                               break;
+                       case "money":
+                               SybaseType = SybaseType.Money;
+                               break;
+                       case "nchar":
+                               SybaseType = SybaseType.NChar;
+                               break;
+                       case "ntext":
+                               SybaseType = SybaseType.NText;
+                               break;
+                       case "nvarchar":
+                               SybaseType = SybaseType.NVarChar;
+                               break;
+                       case "real":
+                               SybaseType = SybaseType.Real;
+                               break;
+                       case "smalldatetime":
+                               SybaseType = SybaseType.SmallDateTime;
+                               break;
+                       case "smallint":
+                               SybaseType = SybaseType.SmallInt;
+                               break;
+                       case "smallmoney":
+                               SybaseType = SybaseType.SmallMoney;
+                               break;
+                       case "text":
+                               SybaseType = SybaseType.Text;
+                               break;
+                       case "timestamp":
+                               SybaseType = SybaseType.Timestamp;
+                               break;
+                       case "tinyint":
+                               SybaseType = SybaseType.TinyInt;
+                               break;
+                       case "uniqueidentifier":
+                               SybaseType = SybaseType.UniqueIdentifier;
+                               break;
+                       case "varbinary":
+                               SybaseType = SybaseType.VarBinary;
+                               break;
+                       case "varchar":
+                               SybaseType = SybaseType.VarChar;
+                               break;
+                       default:
+                               SybaseType = SybaseType.Variant;
+                               break;
+                       }
                }
 
-               internal string Prepare ()
+               // When the SybaseType is set, we also set the DbType, as well as the SQL Server
+               // string representation of the type name.  If the SybaseType is not convertible
+               // to a DbType, throw an exception.
+               private void SetSybaseType (SybaseType type)
                {
-                       StringBuilder result = new StringBuilder ();
-                       result.Append (parmName);
-                       result.Append (" ");
-                       result.Append (dbtype.ToString ());
-
-                       switch (dbtype) {
-                       case SybaseType.Image :
-                       case SybaseType.NVarChar :
-                       case SybaseType.VarBinary :
-                       case SybaseType.VarChar :
-                               if (!sizeSet || size == 0)
-                                       throw new InvalidOperationException ("All variable length parameters must have an explicitly set non-zero size.");
-                               result.Append ("(");
-                               result.Append (size.ToString ());
-                               result.Append (")");
-                               break;
-                       case SybaseType.Decimal :
-                       case SybaseType.Money :
-                       case SybaseType.SmallMoney :
-                               result.Append ("(");
-                               result.Append (precision.ToString ());
-                               result.Append (",");
-                               result.Append (scale.ToString ());
-                               result.Append (")");
-                               break;
-                        default:
-                                break;
-                        }
-
-                        return result.ToString ();
+                       string exception = String.Format ("No mapping exists from SybaseType {0} to a known DbType.", type);
+
+                       switch (type) {
+                       case SybaseType.BigInt:
+                               MetaParameter.TypeName = "bigint";
+                               dbType = DbType.Int64;
+                               break;
+                       case SybaseType.Binary:
+                               MetaParameter.TypeName = "binary";
+                               dbType = DbType.Binary;
+                               break;
+                       case SybaseType.Timestamp:
+                               MetaParameter.TypeName = "timestamp";
+                               dbType = DbType.Binary;
+                               break;
+                       case SybaseType.VarBinary:
+                               MetaParameter.TypeName = "varbinary";
+                               dbType = DbType.Binary;
+                               break;
+                       case SybaseType.Bit:
+                               MetaParameter.TypeName = "bit";
+                               dbType = DbType.Boolean;
+                               break;
+                       case SybaseType.Char:
+                               MetaParameter.TypeName = "char";
+                               dbType = DbType.AnsiStringFixedLength;
+                               break;
+                       case SybaseType.DateTime:
+                               MetaParameter.TypeName = "datetime";
+                               dbType = DbType.DateTime;
+                               break;
+                       case SybaseType.SmallDateTime:
+                               MetaParameter.TypeName = "smalldatetime";
+                               dbType = DbType.DateTime;
+                               break;
+                       case SybaseType.Decimal:
+                               MetaParameter.TypeName = "decimal";
+                               dbType = DbType.Decimal;
+                               break;
+                       case SybaseType.Float:
+                               MetaParameter.TypeName = "float";
+                               dbType = DbType.Double;
+                               break;
+                       case SybaseType.Image:
+                               MetaParameter.TypeName = "image";
+                               dbType = DbType.Binary;
+                               break;
+                       case SybaseType.Int:
+                               MetaParameter.TypeName = "int";
+                               dbType = DbType.Int32;
+                               break;
+                       case SybaseType.Money:
+                               MetaParameter.TypeName = "money";
+                               dbType = DbType.Currency;
+                               break;
+                       case SybaseType.SmallMoney:
+                               MetaParameter.TypeName = "smallmoney";
+                               dbType = DbType.Currency;
+                               break;
+                       case SybaseType.NChar:
+                               MetaParameter.TypeName = "nchar";
+                               dbType = DbType.StringFixedLength;
+                               break;
+                       case SybaseType.NText:
+                               MetaParameter.TypeName = "ntext";
+                               dbType = DbType.String;
+                               break;
+                       case SybaseType.NVarChar:
+                               MetaParameter.TypeName = "nvarchar";
+                               dbType = DbType.String;
+                               break;
+                       case SybaseType.Real:
+                               MetaParameter.TypeName = "real";
+                               dbType = DbType.Single;
+                               break;
+                       case SybaseType.SmallInt:
+                               MetaParameter.TypeName = "smallint";
+                               dbType = DbType.Int16;
+                               break;
+                       case SybaseType.Text:
+                               MetaParameter.TypeName = "text";
+                               dbType = DbType.AnsiString;
+                               break;
+                       case SybaseType.VarChar:
+                               MetaParameter.TypeName = "varchar";
+                               dbType = DbType.AnsiString;
+                               break;
+                       case SybaseType.TinyInt:
+                               MetaParameter.TypeName = "tinyint";
+                               dbType = DbType.Byte;
+                               break;
+                       case SybaseType.UniqueIdentifier:
+                               MetaParameter.TypeName = "uniqueidentifier";
+                               dbType = DbType.Guid;
+                               break;
+                       case SybaseType.Variant:
+                               MetaParameter.TypeName = "sql_variant";
+                               dbType = DbType.Object;
+                               break;
+                       default:
+                               throw new ArgumentException (exception);
+                       }
+                       sybaseType = type;
                }
 
                public override string ToString() 
                {
-                       return parmName;
+                       return ParameterName;
                }
 
                #endregion // Methods