2 // System.Data.Odbc.OdbcParameter
5 // Brian Ritchie (brianlritchie@hotmail.com)
6 // Sureshkumar T <tsureshkumar@novell.com> 2004.
8 // Copyright (C) Brian Ritchie, 2002
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Data.Common;
38 using System.Runtime.InteropServices;
39 using System.Globalization;
40 using System.ComponentModel;
42 namespace System.Data.Odbc
45 [TypeConverterAttribute ("System.Data.Odbc.OdbcParameter+OdbcParameterConverter, " + Consts.AssemblySystem_Data)]
47 [TypeConverterAttribute (typeof (OdbcParameterConverter))]
49 public sealed class OdbcParameter :
55 ICloneable, IDbDataParameter, IDataParameter
60 ParameterDirection direction;
63 DataRowVersion sourceVersion;
69 private OdbcTypeMap _typeMap;
70 private NativeBuffer _nativeBuffer = new NativeBuffer ();
71 private NativeBuffer _cbLengthInd;
72 private OdbcParameterCollection container;
78 public OdbcParameter ()
80 _cbLengthInd = new NativeBuffer ();
81 ParameterName = String.Empty;
83 SourceColumn = String.Empty;
84 Direction = ParameterDirection.Input;
85 _typeMap = OdbcTypeConverter.GetTypeMap (OdbcType.NVarChar);
88 public OdbcParameter (string name, object value)
91 this.ParameterName = name;
93 //FIXME: MS.net does not infer OdbcType from value unless a type is provided
94 _typeMap = OdbcTypeConverter.InferFromValue (value);
95 if (value != null && !value.GetType ().IsValueType) {
96 Type type = value.GetType ();
98 Size = type.GetElementType () == typeof (byte) ?
99 ((Array) value).Length : 0;
101 Size = value.ToString ().Length;
105 public OdbcParameter (string name, OdbcType type)
108 this.ParameterName = name;
109 _typeMap = (OdbcTypeMap) OdbcTypeConverter.GetTypeMap (type);
112 public OdbcParameter (string name, OdbcType type, int size)
118 public OdbcParameter (string name, OdbcType type, int size, string sourcecolumn)
119 : this (name, type, size)
121 this.SourceColumn = sourcecolumn;
124 [EditorBrowsable (EditorBrowsableState.Advanced)]
125 public OdbcParameter (string parameterName, OdbcType odbcType, int size,
126 ParameterDirection parameterDirection, bool isNullable,
127 byte precision, byte scale, string srcColumn,
128 DataRowVersion srcVersion, object value)
129 : this (parameterName, odbcType, size, srcColumn)
131 this.Direction = parameterDirection;
132 this.IsNullable = isNullable;
133 this.SourceVersion = srcVersion;
140 // Used to ensure that only one collection can contain this
142 internal OdbcParameterCollection Container {
143 get { return container; }
144 set { container = value; }
148 [BrowsableAttribute (false)]
149 [RefreshPropertiesAttribute (RefreshProperties.All)]
150 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
152 [OdbcCategory ("Data")]
153 [OdbcDescriptionAttribute ("The parameter generic type")]
159 get { return _typeMap.DbType; }
161 if (value == _typeMap.DbType)
164 _typeMap = OdbcTypeConverter.GetTypeMap (value);
168 [OdbcCategory ("Data")]
169 [OdbcDescriptionAttribute ("Input, output, or bidirectional parameter")]
171 [RefreshPropertiesAttribute (RefreshProperties.All)]
173 [DefaultValue (ParameterDirection.Input)]
179 ParameterDirection Direction {
180 get { return direction; }
181 set { direction = value; }
185 [BrowsableAttribute (false)]
186 [DesignOnlyAttribute (true)]
187 [EditorBrowsableAttribute (EditorBrowsableState.Advanced)]
188 [DefaultValue (false)]
190 [OdbcDescriptionAttribute ("A design-time property used for strongly typed code generation")]
196 get { return isNullable; }
197 set { isNullable = value; }
200 [DefaultValue (OdbcType.NChar)]
201 [OdbcDescriptionAttribute ("The parameter native type")]
202 [RefreshPropertiesAttribute (RefreshProperties.All)]
203 [OdbcCategory ("Data")]
205 [DbProviderSpecificTypeProperty (true)]
207 public OdbcType OdbcType {
208 get { return _typeMap.OdbcType; }
210 if (value == _typeMap.OdbcType)
213 _typeMap = OdbcTypeConverter.GetTypeMap (value);
217 [OdbcDescription ("DataParameter_ParameterName")]
225 string ParameterName {
227 set { name = value; }
230 [OdbcDescription ("DbDataParameter_Precision")]
231 [OdbcCategory ("DataCategory_Data")]
233 public byte Precision {
234 get { return _precision; }
235 set { _precision = value; }
238 [OdbcDescription ("DbDataParameter_Scale")]
239 [OdbcCategory ("DataCategory_Data")]
242 get { return _scale; }
243 set { _scale = value; }
246 [OdbcDescription ("DbDataParameter_Size")]
247 [OdbcCategory ("DataCategory_Data")]
257 set { size = value; }
260 [OdbcDescription ("DataParameter_SourceColumn")]
261 [OdbcCategory ("DataCategory_Data")]
269 string SourceColumn {
270 get { return sourceColumn; }
271 set { sourceColumn = value; }
274 [OdbcDescription ("DataParameter_SourceVersion")]
275 [OdbcCategory ("DataCategory_Data")]
277 [DefaultValue ("Current")]
283 DataRowVersion SourceVersion {
284 get { return sourceVersion; }
285 set { sourceVersion = value; }
288 [TypeConverter (typeof(StringConverter))]
289 [OdbcDescription ("DataParameter_Value")]
290 [OdbcCategory ("DataCategory_Data")]
292 [DefaultValue (null)]
294 [RefreshPropertiesAttribute (RefreshProperties.All)]
301 get { return _value; }
302 set { _value = value; }
305 #endregion // Properties
309 internal void Bind (OdbcCommand command, IntPtr hstmt, int ParamNum)
314 // Convert System.Data.ParameterDirection into odbc enum
315 OdbcInputOutputDirection paramdir = libodbc.ConvertParameterDirection (this.Direction);
317 _cbLengthInd.EnsureAlloc (Marshal.SizeOf (typeof (int)));
319 len = (int)OdbcLengthIndicator.NullData;
321 len = GetNativeSize ();
325 Marshal.WriteInt32 (_cbLengthInd, len);
326 ret = libodbc.SQLBindParameter (hstmt, (ushort) ParamNum, (short) paramdir,
327 _typeMap.NativeType, _typeMap.SqlType, Convert.ToUInt32 (Size),
328 0, (IntPtr) _nativeBuffer, 0, _cbLengthInd);
330 // Check for error condition
331 if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
332 throw command.Connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);
336 object ICloneable.Clone ()
338 throw new NotImplementedException ();
341 public override string ToString ()
343 return ParameterName;
346 private int GetNativeSize ()
348 TextInfo ti = CultureInfo.InvariantCulture.TextInfo;
349 Encoding enc = Encoding.GetEncoding (ti.ANSICodePage);
351 switch (_typeMap.OdbcType) {
352 case OdbcType.Binary:
353 if (Value.GetType ().IsArray &&
354 Value.GetType ().GetElementType () == typeof (byte))
355 return ( (Array) Value).Length;
357 return Value.ToString ().Length;
359 return Marshal.SizeOf (typeof (byte));
360 case OdbcType.Double:
361 return Marshal.SizeOf (typeof (double));
363 return Marshal.SizeOf (typeof (float));
365 return Marshal.SizeOf (typeof (int));
366 case OdbcType.BigInt:
367 return Marshal.SizeOf (typeof (long));
368 case OdbcType.Decimal:
369 case OdbcType.Numeric:
371 case OdbcType.SmallInt:
372 return Marshal.SizeOf (typeof (Int16));
373 case OdbcType.TinyInt:
374 return Marshal.SizeOf (typeof (byte));
377 case OdbcType.VarChar:
378 return enc.GetByteCount (Convert.ToString (Value)) + 1;
381 case OdbcType.NVarChar:
382 // FIXME: Change to unicode
383 return enc.GetByteCount (Convert.ToString (Value)) + 1;
384 case OdbcType.VarBinary:
386 if (Value.GetType ().IsArray &&
387 Value.GetType ().GetElementType () == typeof (byte))
388 return ((Array) Value).Length;
389 throw new ArgumentException ("Unsupported Native Type!");
391 case OdbcType.DateTime:
392 case OdbcType.SmallDateTime:
394 case OdbcType.Timestamp:
396 case OdbcType.UniqueIdentifier:
397 return Marshal.SizeOf (typeof (Guid));
400 if (Value.GetType ().IsArray &&
401 Value.GetType ().GetElementType () == typeof (byte))
402 return ((Array) Value).Length;
404 return Value.ToString ().Length;
407 private void AllocateBuffer ()
409 int size = GetNativeSize ();
411 if (_nativeBuffer.Size == size)
414 _nativeBuffer.AllocBuffer (size);
417 internal void CopyValue ()
419 if (_nativeBuffer.Handle == IntPtr.Zero)
426 TextInfo ti = CultureInfo.InvariantCulture.TextInfo;
427 Encoding enc = Encoding.GetEncoding (ti.ANSICodePage);
428 byte [] nativeBytes, buffer;
430 switch (_typeMap.OdbcType) {
432 Marshal.WriteByte (_nativeBuffer, Convert.ToByte (Value));
434 case OdbcType.Double:
435 Marshal.StructureToPtr (Convert.ToDouble (Value), _nativeBuffer, false);
438 Marshal.StructureToPtr (Convert.ToSingle (Value), _nativeBuffer, false);
441 Marshal.WriteInt32 (_nativeBuffer, Convert.ToInt32 (Value));
443 case OdbcType.BigInt:
444 Marshal.WriteInt64 (_nativeBuffer, Convert.ToInt64 (Value));
446 case OdbcType.Decimal:
447 case OdbcType.Numeric:
448 // for numeric, the buffer is a packed decimal struct.
449 // ref http://www.it-faq.pl/mskb/181/254.HTM
450 int [] bits = Decimal.GetBits (Convert.ToDecimal (Value));
451 buffer = new byte [19]; // ref sqltypes.h
452 buffer [0] = Precision;
453 buffer [1] = (byte) ((bits [3] & 0x00FF0000) >> 16); // scale
454 buffer [2] = (byte) ((bits [3] & 0x80000000) > 0 ? 2 : 1); //sign
455 Buffer.BlockCopy (bits, 0, buffer, 3, 12); // copy data
456 for (int j = 16; j < 19; j++) // pad with 0
458 Marshal.Copy (buffer, 0, _nativeBuffer, 19);
460 case OdbcType.SmallInt:
461 Marshal.WriteInt16 (_nativeBuffer, Convert.ToInt16 (Value));
463 case OdbcType.TinyInt:
464 Marshal.WriteByte (_nativeBuffer, Convert.ToByte (Value));
468 case OdbcType.VarChar:
469 buffer = new byte [GetNativeSize ()];
470 nativeBytes = enc.GetBytes (Convert.ToString (Value));
471 Array.Copy (nativeBytes, 0, buffer, 0, nativeBytes.Length);
472 buffer [buffer.Length-1] = (byte) 0;
473 Marshal.Copy (buffer, 0, _nativeBuffer, buffer.Length);
474 Marshal.WriteInt32 (_cbLengthInd, -3);
478 case OdbcType.NVarChar:
479 // FIXME : change to unicode
480 buffer = new byte [GetNativeSize ()];
481 nativeBytes = enc.GetBytes (Convert.ToString (Value));
482 Array.Copy (nativeBytes, 0, buffer, 0, nativeBytes.Length);
483 buffer [buffer.Length-1] = (byte) 0;
484 Marshal.Copy (buffer, 0, _nativeBuffer, buffer.Length);
485 Marshal.WriteInt32 (_cbLengthInd, -3);
487 case OdbcType.VarBinary:
489 case OdbcType.Binary:
490 if (Value.GetType ().IsArray &&
491 Value.GetType ().GetElementType () == typeof (byte)) {
492 Marshal.Copy ( (byte []) Value, 0, _nativeBuffer, ((byte []) Value).Length);
494 throw new ArgumentException ("Unsupported Native Type!");
497 dt = (DateTime) Value;
498 Marshal.WriteInt16 (_nativeBuffer, 0, (short) dt.Year);
499 Marshal.WriteInt16 (_nativeBuffer, 2, (short) dt.Month);
500 Marshal.WriteInt16 (_nativeBuffer, 4, (short) dt.Day);
503 dt = (DateTime) Value;
504 Marshal.WriteInt16 (_nativeBuffer, 0, (short) dt.Hour);
505 Marshal.WriteInt16 (_nativeBuffer, 2, (short) dt.Minute);
506 Marshal.WriteInt16 (_nativeBuffer, 4, (short) dt.Second);
508 case OdbcType.SmallDateTime:
509 case OdbcType.Timestamp:
510 case OdbcType.DateTime:
511 dt = (DateTime) Value;
512 Marshal.WriteInt16 (_nativeBuffer, 0, (short) dt.Year);
513 Marshal.WriteInt16 (_nativeBuffer, 2, (short) dt.Month);
514 Marshal.WriteInt16 (_nativeBuffer, 4, (short) dt.Day);
515 Marshal.WriteInt16 (_nativeBuffer, 6, (short) dt.Hour);
516 Marshal.WriteInt16 (_nativeBuffer, 8, (short) dt.Minute);
517 Marshal.WriteInt16 (_nativeBuffer, 10, (short) dt.Second);
518 Marshal.WriteInt32 (_nativeBuffer, 12, (int) (dt.Ticks % 10000000) * 100);
520 case OdbcType.UniqueIdentifier:
521 throw new NotImplementedException ();
524 if (Value.GetType ().IsArray &&
525 Value.GetType ().GetElementType () == typeof (byte)) {
526 Marshal.Copy ( (byte []) Value, 0, _nativeBuffer, ((byte []) Value).Length);
528 throw new ArgumentException ("Unsupported Native Type!");
532 public override bool SourceColumnNullMapping {
533 get { return false; }
537 public override void ResetDbType ()
539 _typeMap = OdbcTypeConverter.GetTypeMap (OdbcType.NVarChar);
542 public void ResetOdbcType ()
544 _typeMap = OdbcTypeConverter.GetTypeMap (OdbcType.NVarChar);