//
// Authors:
// Brian Ritchie (brianlritchie@hotmail.com)
+// Sureshkumar T <tsureshkumar@novell.com> 2004.
//
// Copyright (C) Brian Ritchie, 2002
//
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// 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 System;
+using System.Text;
using System.Data;
using System.Data.Common;
+using System.Runtime.InteropServices;
+using System.Globalization;
+using System.ComponentModel;
namespace System.Data.Odbc
{
+ [TypeConverterAttribute (typeof (OdbcParameterConverter))]
+#if NET_2_0
+ public sealed class OdbcParameter : DbParameter, ICloneable
+#else
public sealed class OdbcParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
+#endif // NET_2_0
{
#region Fields
string name;
- object value;
- int size;
+ ParameterDirection direction;
bool isNullable;
- byte precision;
- byte scale;
+ int size;
DataRowVersion sourceVersion;
string sourceColumn;
- ParameterDirection direction;
- OdbcType odbcType;
- DbType dbType;
-
- int IntValue;
+ byte _precision;
+ byte _scale;
+ object _value;
+ private OdbcTypeMap _typeMap;
+ private NativeBuffer _nativeBuffer = new NativeBuffer ();
+ private NativeBuffer _cbLengthInd;
+ private OdbcParameterCollection container = null;
+
#endregion
#region Constructors
public OdbcParameter ()
{
- name = String.Empty;
- value = null;
- size = 0;
- isNullable = true;
- precision = 0;
- scale = 0;
- sourceColumn = String.Empty;
+ _cbLengthInd = new NativeBuffer ();
+ ParameterName = String.Empty;
+ IsNullable = false;
+ SourceColumn = String.Empty;
+ Direction = ParameterDirection.Input;
+ _typeMap = OdbcTypeConverter.GetTypeMap (OdbcType.NVarChar);
}
public OdbcParameter (string name, object value)
: this ()
{
- this.name = name;
- this.value = value;
+ this.ParameterName = name;
+ Value = value;
+ //FIXME: MS.net does not infer OdbcType from value unless a type is provided
+ _typeMap = OdbcTypeConverter.InferFromValue (value);
+ if (value != null && !value.GetType ().IsValueType) {
+ Type type = value.GetType ();
+ if (type.IsArray)
+ Size = type.GetElementType () == typeof (byte) ?
+ ((Array) value).Length : 0;
+ else
+ Size = value.ToString ().Length;
+ }
}
- public OdbcParameter (string name, OdbcType dataType)
+ public OdbcParameter (string name, OdbcType odbcType)
: this ()
{
- this.name = name;
- OdbcType = dataType;
-
- // These paramter types aren't supported yet...
- if (odbcType==OdbcType.Date || odbcType==OdbcType.Time || odbcType==OdbcType.DateTime ||
- OdbcType==OdbcType.Timestamp || odbcType==OdbcType.SmallDateTime)
- throw new NotSupportedException();
+ this.ParameterName = name;
+ _typeMap = (OdbcTypeMap) OdbcTypeConverter.GetTypeMap (odbcType);
}
- public OdbcParameter (string name, OdbcType dataType, int size)
- : this (name, dataType)
+ public OdbcParameter (string name, OdbcType odbcType, int size)
+ : this (name, odbcType)
{
- this.size = size;
+ this.Size = size;
}
- public OdbcParameter (string name, OdbcType dataType, int size, string srcColumn)
- : this (name, dataType, size)
+ public OdbcParameter (string name, OdbcType odbcType, int size, string srcColumn)
+ : this (name, odbcType, size)
{
- this.sourceColumn = srcColumn;
+ this.SourceColumn = srcColumn;
}
- public OdbcParameter(string name, OdbcType dataType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string srcColumn, DataRowVersion srcVersion, object value)
- : this (name, dataType, size, srcColumn)
+ [EditorBrowsable (EditorBrowsableState.Advanced)]
+ public OdbcParameter(string name, OdbcType odbcType, int size,
+ ParameterDirection direction, bool isNullable,
+ byte precision, byte scale, string srcColumn,
+ DataRowVersion srcVersion, object value)
+ : this (name, odbcType, size, srcColumn)
{
- this.direction = direction;
- this.isNullable = isNullable;
- this.precision = precision;
- this.scale = scale;
- this.sourceVersion = srcVersion;
- this.value = value;
+ this.Direction = direction;
+ this.IsNullable = isNullable;
+ this.SourceVersion = srcVersion;
}
#endregion
#region Properties
- public DbType DbType {
- get { return dbType; }
+ // Used to ensure that only one collection can contain this
+ // parameter
+ internal OdbcParameterCollection Container {
+ get { return container; }
+ set { container = value; }
+ }
+
+ [BrowsableAttribute (false)]
+ [OdbcDescriptionAttribute ("The parameter generic type")]
+ [RefreshPropertiesAttribute (RefreshProperties.All)]
+ [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
+ [OdbcCategory ("Data")]
+ public
+#if NET_2_0
+ override
+#endif
+ DbType DbType {
+ get { return _typeMap.DbType; }
set {
- dbType = value;
+ if (value == _typeMap.DbType)
+ return;
+
+ _typeMap = OdbcTypeConverter.GetTypeMap (value);
}
}
- public ParameterDirection Direction {
+ [OdbcCategory ("Data")]
+ [OdbcDescriptionAttribute ("Input, output, or bidirectional parameter")]
+ [DefaultValue (ParameterDirection.Input)]
+ public
+#if NET_2_0
+ override
+#endif
+ ParameterDirection Direction {
get { return direction; }
set { direction = value; }
}
- public bool IsNullable {
+ [BrowsableAttribute (false)]
+ [OdbcDescriptionAttribute ("A design-time property used for strongly typed code generation")]
+ [DesignOnlyAttribute (true)]
+ [EditorBrowsableAttribute (EditorBrowsableState.Advanced)]
+ [DefaultValue (false)]
+ public
+#if NET_2_0
+ override
+#endif
+ bool IsNullable {
get { return isNullable; }
+ set { isNullable = value; }
}
+
+ [DefaultValue (OdbcType.NChar)]
+ [OdbcDescriptionAttribute ("The parameter native type")]
+ [RefreshPropertiesAttribute (RefreshProperties.All)]
+ [OdbcCategory ("Data")]
public OdbcType OdbcType {
- get { return odbcType; }
+ get { return _typeMap.OdbcType; }
set {
- odbcType = value;
+ if (value == OdbcType)
+ return;
+
+ _typeMap = OdbcTypeConverter.GetTypeMap (value);
}
}
- public string ParameterName {
+ [OdbcDescription ("DataParameter_ParameterName")]
+ [DefaultValue ("")]
+ public
+#if NET_2_0
+ override
+#endif
+ string ParameterName {
get { return name; }
set { name = value; }
}
+ [OdbcDescription ("DbDataParameter_Precision")]
+ [OdbcCategory ("DataCategory_Data")]
+ [DefaultValue (0)]
public byte Precision {
- get { return precision; }
- set { precision = value; }
+ get { return _precision; }
+ set { _precision = value; }
}
+ [OdbcDescription ("DbDataParameter_Scale")]
+ [OdbcCategory ("DataCategory_Data")]
+ [DefaultValue (0)]
public byte Scale {
- get { return scale; }
- set { scale = value; }
+ get { return _scale; }
+ set { _scale = value; }
}
- public int Size {
+ [OdbcDescription ("DbDataParameter_Size")]
+ [OdbcCategory ("DataCategory_Data")]
+ [DefaultValue (0)]
+ public
+#if NET_2_0
+ override
+#endif
+ int Size {
get { return size; }
set { size = value; }
}
- public string SourceColumn {
+ [OdbcDescription ("DataParameter_SourceColumn")]
+ [OdbcCategory ("DataCategory_Data")]
+ [DefaultValue ("")]
+ public
+#if NET_2_0
+ override
+#endif
+ string SourceColumn {
get { return sourceColumn; }
set { sourceColumn = value; }
}
- public DataRowVersion SourceVersion {
+ [OdbcDescription ("DataParameter_SourceVersion")]
+ [OdbcCategory ("DataCategory_Data")]
+ [DefaultValue ("Current")]
+ public
+#if NET_2_0
+ override
+#endif
+ DataRowVersion SourceVersion {
get { return sourceVersion; }
set { sourceVersion = value; }
}
-
- public object Value {
+
+ [TypeConverter (typeof(StringConverter))]
+ [OdbcDescription ("DataParameter_Value")]
+ [OdbcCategory ("DataCategory_Data")]
+ [DefaultValue (null)]
+ public
+#if NET_2_0
+ override
+#endif
+ object Value {
get {
- return IntValue;
+ return _value;
+ }
+ set {
+ _value = value;
}
- set { this.IntValue =(int) value; }
}
#endregion // Properties
- #region Internal Properties
+ #region Methods
- internal void Bind(IntPtr hstmt,int ParamNum)
- {
- OdbcReturn ret=libodbc.SQLBindParam(hstmt, Convert.ToInt16(ParamNum), (short) odbcType, (short) odbcType, 0,0,ref IntValue, 0);
- libodbchelper.DisplayError("SQLBindParam",ret);
- }
-
- #endregion // Internal Properties
+ internal void Bind(IntPtr hstmt, int ParamNum) {
+ OdbcReturn ret;
+
+ // Convert System.Data.ParameterDirection into odbc enum
+ OdbcInputOutputDirection paramdir = libodbc.ConvertParameterDirection(this.Direction);
- #region Methods
+ _cbLengthInd.EnsureAlloc (Marshal.SizeOf (typeof (int)));
+ Marshal.WriteInt32 (_cbLengthInd, GetNativeSize ());
+ AllocateBuffer ();
+ ret = libodbc.SQLBindParameter(hstmt, (ushort) ParamNum, (short) paramdir,
+ _typeMap.NativeType, _typeMap.SqlType, Convert.ToUInt32(Size),
+ 0, (IntPtr) _nativeBuffer, 0, _cbLengthInd);
+
+ // Check for error condition
+ if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
+ throw new OdbcException(new OdbcError("SQLBindParam", OdbcHandleType.Stmt, hstmt));
+ }
[MonoTODO]
object ICloneable.Clone ()
{
return ParameterName;
}
+
+ private int GetNativeSize ()
+ {
+ TextInfo ti = CultureInfo.InvariantCulture.TextInfo;
+ Encoding enc = Encoding.GetEncoding (ti.ANSICodePage);
+
+ switch (_typeMap.OdbcType) {
+ case OdbcType.Binary:
+ if (Value.GetType ().IsArray &&
+ Value.GetType ().GetElementType () == typeof (byte))
+ return ( (Array) Value).Length;
+ else
+ return Value.ToString ().Length;
+ case OdbcType.Bit:
+ return Marshal.SizeOf (typeof (byte));
+ case OdbcType.Double:
+ return Marshal.SizeOf (typeof (double));
+ case OdbcType.Real:
+ return Marshal.SizeOf (typeof (float));
+ case OdbcType.Int:
+ return Marshal.SizeOf (typeof (int));
+ case OdbcType.BigInt:
+ return Marshal.SizeOf (typeof (long));
+ case OdbcType.Decimal:
+ case OdbcType.Numeric:
+ return 19;
+ case OdbcType.SmallInt:
+ return Marshal.SizeOf (typeof (Int16));
+ case OdbcType.TinyInt:
+ return Marshal.SizeOf (typeof (byte));
+ case OdbcType.Char:
+ case OdbcType.Text:
+ case OdbcType.VarChar:
+ return enc.GetByteCount (Convert.ToString (Value)) + 1;
+ case OdbcType.NChar:
+ case OdbcType.NText:
+ case OdbcType.NVarChar:
+ // FIXME: Change to unicode
+ return enc.GetByteCount (Convert.ToString (Value)) + 1;
+ case OdbcType.VarBinary:
+ case OdbcType.Image:
+ if (Value.GetType ().IsArray &&
+ Value.GetType ().GetElementType () == typeof (byte))
+ return ( (Array) Value).Length;
+ throw new ArgumentException ("Unsupported Native Type!");
+ case OdbcType.Date:
+ case OdbcType.DateTime:
+ case OdbcType.SmallDateTime:
+ case OdbcType.Time:
+ case OdbcType.Timestamp:
+ return 18;
+ case OdbcType.UniqueIdentifier:
+ return Marshal.SizeOf (typeof (Guid));
+ }
+
+ if (Value.GetType ().IsArray &&
+ Value.GetType ().GetElementType () == typeof (byte))
+ return ( (Array) Value).Length;
+
+ return Value.ToString ().Length;
+ }
+
+ private void AllocateBuffer ()
+ {
+ int size = GetNativeSize ();
+
+ if (_nativeBuffer.Size == size)
+ return;
+
+ _nativeBuffer.AllocBuffer (size);
+ }
+
+ internal void CopyValue ()
+ {
+ if (_nativeBuffer.Handle == IntPtr.Zero)
+ return;
+
+ DateTime dt;
+ TextInfo ti = CultureInfo.InvariantCulture.TextInfo;
+ Encoding enc = Encoding.GetEncoding (ti.ANSICodePage);
+ byte [] nativeBytes, buffer;
+
+ switch (_typeMap.OdbcType) {
+ case OdbcType.Binary:
+ throw new NotImplementedException ();
+ case OdbcType.Bit:
+ Marshal.WriteByte (_nativeBuffer, Convert.ToByte (Value));
+ return;
+ case OdbcType.Double:
+ Marshal.StructureToPtr (Convert.ToDouble (Value), _nativeBuffer, false);
+ return;
+ case OdbcType.Real:
+ Marshal.StructureToPtr (Convert.ToSingle (Value), _nativeBuffer, false);
+ return;
+ case OdbcType.Int:
+ Marshal.WriteInt32 (_nativeBuffer, Convert.ToInt32 (Value));
+ return;
+ case OdbcType.BigInt:
+ Marshal.WriteInt64 (_nativeBuffer, Convert.ToInt64 (Value));
+ return;
+ case OdbcType.Decimal:
+ case OdbcType.Numeric:
+ // for numeric, the buffer is a packed decimal struct.
+ // ref http://www.it-faq.pl/mskb/181/254.HTM
+ int [] bits = Decimal.GetBits (Convert.ToDecimal (Value));
+ buffer = new byte [19]; // ref sqltypes.h
+ buffer [0] = Precision;
+ buffer [1] = (byte) ((bits [3] & 0x00FF0000) >> 16); // scale
+ buffer [2] = (byte) ((bits [3] & 0x80000000) > 0 ? 2 : 1); //sign
+ Buffer.BlockCopy (bits, 0, buffer, 3, 12); // copy data
+ for (int j = 16; j < 19; j++) // pad with 0
+ buffer [j] = 0;
+ Marshal.Copy (buffer, 0, _nativeBuffer, 19);
+ return;
+ case OdbcType.SmallInt:
+ Marshal.WriteInt16 (_nativeBuffer, Convert.ToInt16 (Value));
+ return;
+ case OdbcType.TinyInt:
+ Marshal.WriteByte (_nativeBuffer, Convert.ToByte (Value));
+ return;
+ case OdbcType.Char:
+ case OdbcType.Text:
+ case OdbcType.VarChar:
+ buffer = new byte [GetNativeSize ()];
+ nativeBytes = enc.GetBytes (Convert.ToString (Value));
+ Array.Copy (nativeBytes, 0, buffer, 0, nativeBytes.Length);
+ buffer [buffer.Length-1] = (byte) 0;
+ Marshal.Copy (buffer, 0, _nativeBuffer, buffer.Length);
+ Marshal.WriteInt32 (_cbLengthInd, -3);
+ return;
+ case OdbcType.NChar:
+ case OdbcType.NText:
+ case OdbcType.NVarChar:
+ // FIXME : change to unicode
+ buffer = new byte [GetNativeSize ()];
+ nativeBytes = enc.GetBytes (Convert.ToString (Value));
+ Array.Copy (nativeBytes, 0, buffer, 0, nativeBytes.Length);
+ buffer [buffer.Length-1] = (byte) 0;
+ Marshal.Copy (buffer, 0, _nativeBuffer, buffer.Length);
+ Marshal.WriteInt32 (_cbLengthInd, -3);
+ return;
+ case OdbcType.VarBinary:
+ case OdbcType.Image:
+ if (Value.GetType ().IsArray &&
+ Value.GetType ().GetElementType () == typeof (byte)) {
+ Marshal.Copy ( (byte []) Value, 0, _nativeBuffer, ((byte []) Value).Length);
+ }else
+ throw new ArgumentException ("Unsupported Native Type!");
+ return;
+ case OdbcType.Date:
+ dt = (DateTime) Value;
+ Marshal.WriteInt16 (_nativeBuffer, 0, (short) dt.Year);
+ Marshal.WriteInt16 (_nativeBuffer, 2, (short) dt.Month);
+ Marshal.WriteInt16 (_nativeBuffer, 4, (short) dt.Day);
+ return;
+ case OdbcType.Time:
+ dt = (DateTime) Value;
+ Marshal.WriteInt16 (_nativeBuffer, 0, (short) dt.Hour);
+ Marshal.WriteInt16 (_nativeBuffer, 2, (short) dt.Minute);
+ Marshal.WriteInt16 (_nativeBuffer, 4, (short) dt.Second);
+ return;
+ case OdbcType.SmallDateTime:
+ case OdbcType.Timestamp:
+ case OdbcType.DateTime:
+ dt = (DateTime) Value;
+ Marshal.WriteInt16 (_nativeBuffer, 0, (short) dt.Year);
+ Marshal.WriteInt16 (_nativeBuffer, 2, (short) dt.Month);
+ Marshal.WriteInt16 (_nativeBuffer, 4, (short) dt.Day);
+ Marshal.WriteInt16 (_nativeBuffer, 6, (short) dt.Hour);
+ Marshal.WriteInt16 (_nativeBuffer, 8, (short) dt.Minute);
+ Marshal.WriteInt16 (_nativeBuffer, 10, (short) dt.Second);
+ Marshal.WriteInt32 (_nativeBuffer, 12, (int) (dt.Ticks % 10000000) * 100);
+ return;
+ case OdbcType.UniqueIdentifier:
+ throw new NotImplementedException ();
+ }
+
+ if (Value.GetType ().IsArray &&
+ Value.GetType ().GetElementType () == typeof (byte)) {
+ Marshal.Copy ( (byte []) Value, 0, _nativeBuffer, ((byte []) Value).Length);
+ }else
+ throw new ArgumentException ("Unsupported Native Type!");
+ }
+
+#if NET_2_0
+ public override bool SourceColumnNullMapping {
+ get {return false;}
+ set {}
+ }
+
+ public override void ResetDbType ()
+ {
+ throw new NotImplementedException ();
+ }
+#endif
+
#endregion
}
}