//
// Authors:
// Brian Ritchie (brianlritchie@hotmail.com)
+// Sureshkumar T <tsureshkumar@novell.com> 2004.
//
// Copyright (C) Brian Ritchie, 2002
//
//
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))]
+ [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 ParamValue;
- int size;
+ ParameterDirection direction;
bool isNullable;
- byte precision;
- byte scale;
+ int size;
DataRowVersion sourceVersion;
string sourceColumn;
- ParameterDirection direction;
- OdbcType odbcType;
- DbType dbType;
- OdbcParameterCollection container = null;
-
- // Buffers for parameter value based on type. Currently I've only optimized
- // for int parameters and everything else is just converted to a string.
- private bool bufferIsSet;
- int intbuf;
- byte[] buffer;
+ 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;
- ParamValue = 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.ParamValue = value;
-
- if (value != null && !value.GetType ().IsValueType) {
- Type type = value.GetType ();
- if (type.IsArray)
- size = type.GetElementType () == typeof (byte) ?
+ 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;
+ else
+ Size = value.ToString ().Length;
}
-
-
}
- public OdbcParameter (string name, OdbcType dataType)
+ public OdbcParameter (string name, OdbcType odbcType)
: this ()
{
- this.name = name;
- OdbcType = dataType;
+ 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;
}
[EditorBrowsable (EditorBrowsableState.Advanced)]
- 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)
+ 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.ParamValue = value;
+ this.Direction = direction;
+ this.IsNullable = isNullable;
+ this.SourceVersion = srcVersion;
}
#endregion
[RefreshPropertiesAttribute (RefreshProperties.All)]
[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
[OdbcCategory ("Data")]
- public DbType DbType {
- get { return dbType; }
+ 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);
}
}
[OdbcCategory ("Data")]
[OdbcDescriptionAttribute ("Input, output, or bidirectional parameter")]
[DefaultValue (ParameterDirection.Input)]
- public ParameterDirection Direction {
+ public
+#if NET_2_0
+ override
+#endif
+ ParameterDirection Direction {
get { return direction; }
set { direction = value; }
}
[DesignOnlyAttribute (true)]
[EditorBrowsableAttribute (EditorBrowsableState.Advanced)]
[DefaultValue (false)]
- public bool IsNullable {
- get { return isNullable; }\r
- set { isNullable = value; }\r
+ 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);
}
}
[OdbcDescription ("DataParameter_ParameterName")]
[DefaultValue ("")]
- public string ParameterName {
+ public
+#if NET_2_0
+ override
+#endif
+ string ParameterName {
get { return name; }
set { name = value; }
}
[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; }
}
[OdbcDescription ("DbDataParameter_Size")]
[OdbcCategory ("DataCategory_Data")]
[DefaultValue (0)]
- public int Size {
+ public
+#if NET_2_0
+ override
+#endif
+ int Size {
get { return size; }
set { size = value; }
}
[OdbcDescription ("DataParameter_SourceColumn")]
[OdbcCategory ("DataCategory_Data")]
[DefaultValue ("")]
- public string SourceColumn {
+ public
+#if NET_2_0
+ override
+#endif
+ string SourceColumn {
get { return sourceColumn; }
set { sourceColumn = value; }
}
[OdbcDescription ("DataParameter_SourceVersion")]
[OdbcCategory ("DataCategory_Data")]
- [DefaultValue (512)]
- public DataRowVersion SourceVersion {
+ [DefaultValue ("Current")]
+ public
+#if NET_2_0
+ override
+#endif
+ DataRowVersion SourceVersion {
get { return sourceVersion; }
set { sourceVersion = value; }
}
[OdbcDescription ("DataParameter_Value")]
[OdbcCategory ("DataCategory_Data")]
[DefaultValue (null)]
- public object Value {
+ public
+#if NET_2_0
+ override
+#endif
+ object Value {
get {
- return ParamValue;
+ return _value;
}
set {
- this.ParamValue = value;
- bufferIsSet = false;
+ _value = value;
}
}
#endregion // Properties
- #region Methods\r
-\r
- internal void Bind(IntPtr hstmt, int ParamNum) {\r
- OdbcReturn ret;\r
- // Set up the buffer if we haven't done so yet\r
- if (!bufferIsSet)\r
- setBuffer();\r
-\r
- // Convert System.Data.ParameterDirection into odbc enum\r
- OdbcInputOutputDirection paramdir = libodbc.ConvertParameterDirection(this.direction);\r
- // Bind parameter based on type\r
- if (odbcType == OdbcType.Int)\r
- ret = libodbc.SQLBindParameter(hstmt, (ushort)ParamNum, (short)paramdir,\r
- (short)odbcType, (short)odbcType, Convert.ToUInt32(size),\r
- 0, ref intbuf, 0, 0);\r
- else\r
- ret = libodbc.SQLBindParameter(hstmt, (ushort)ParamNum, (short)paramdir,\r
- (short)OdbcType.Char, (short)odbcType, Convert.ToUInt32(size),\r
- 0, buffer, 0, 0);\r
- // Check for error condition\r
- if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))\r
- throw new OdbcException(new OdbcError("SQLBindParam", OdbcHandleType.Stmt, hstmt));\r
- }\r
-\r
- private void setBuffer() {\r
- // Load buffer with new value
- if (odbcType == OdbcType.Int)
- intbuf = ParamValue == null ? new int () : (int) ParamValue;
- else {\r
- string paramValueString = ParamValue.ToString();\r
- // Treat everything else as a string\r
- // Init string buffer\r
- if (ParamValue is String)
- paramValueString = "\'"+paramValueString+"\'";
-
- int minSize = size;
- minSize = size > 20 ? size : 20;
- if (buffer == null || buffer.Length < minSize)
- buffer = new byte[minSize];
- else
- buffer.Initialize();
-
- // Convert value into string and store into buffer
- minSize = paramValueString.Length < minSize ? paramValueString.Length : minSize;
- System.Text.Encoding.ASCII.GetBytes(paramValueString, 0, minSize, buffer, 0);\r
- }\r
- bufferIsSet = true;\r
- }\r
-\r
+ #region Methods
+
+ internal void Bind(IntPtr hstmt, int ParamNum) {
+ OdbcReturn ret;
+
+ // Convert System.Data.ParameterDirection into odbc enum
+ OdbcInputOutputDirection paramdir = libodbc.ConvertParameterDirection(this.Direction);
+
+ _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
}
}