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
44 [TypeConverterAttribute ("System.Data.Odbc.OdbcParameter+OdbcParameterConverter, " + Consts
.AssemblySystem_Data
)]
45 public sealed class OdbcParameter
:
47 ICloneable
, IDbDataParameter
, IDataParameter
52 ParameterDirection direction
;
55 DataRowVersion sourceVersion
;
61 private OdbcTypeMap _typeMap
;
62 private NativeBuffer _nativeBuffer
= new NativeBuffer ();
63 private NativeBuffer _cbLengthInd
;
64 private OdbcParameterCollection container
;
70 public OdbcParameter ()
72 _cbLengthInd
= new NativeBuffer ();
73 ParameterName
= String
.Empty
;
75 SourceColumn
= String
.Empty
;
76 Direction
= ParameterDirection
.Input
;
77 _typeMap
= OdbcTypeConverter
.GetTypeMap (OdbcType
.NVarChar
);
80 public OdbcParameter (string name
, object value)
83 this.ParameterName
= name
;
85 //FIXME: MS.net does not infer OdbcType from value unless a type is provided
86 _typeMap
= OdbcTypeConverter
.InferFromValue (value);
87 if (value != null && !value.GetType ().IsValueType
) {
88 Type type
= value.GetType ();
90 Size
= type
.GetElementType () == typeof (byte) ?
91 ((Array
) value).Length
: 0;
93 Size
= value.ToString ().Length
;
97 public OdbcParameter (string name
, OdbcType type
)
100 this.ParameterName
= name
;
101 _typeMap
= (OdbcTypeMap
) OdbcTypeConverter
.GetTypeMap (type
);
104 public OdbcParameter (string name
, OdbcType type
, int size
)
110 public OdbcParameter (string name
, OdbcType type
, int size
, string sourcecolumn
)
111 : this (name
, type
, size
)
113 this.SourceColumn
= sourcecolumn
;
116 [EditorBrowsable (EditorBrowsableState
.Advanced
)]
117 public OdbcParameter (string parameterName
, OdbcType odbcType
, int size
,
118 ParameterDirection parameterDirection
, bool isNullable
,
119 byte precision
, byte scale
, string srcColumn
,
120 DataRowVersion srcVersion
, object value)
121 : this (parameterName
, odbcType
, size
, srcColumn
)
123 this.Direction
= parameterDirection
;
124 this.IsNullable
= isNullable
;
125 this.SourceVersion
= srcVersion
;
132 // Used to ensure that only one collection can contain this
134 internal OdbcParameterCollection Container
{
135 get { return container; }
136 set { container = value; }
139 [OdbcCategory ("Data")]
140 [OdbcDescriptionAttribute ("The parameter generic type")]
144 get { return _typeMap.DbType; }
146 if (value == _typeMap
.DbType
)
149 _typeMap
= OdbcTypeConverter
.GetTypeMap (value);
153 [OdbcCategory ("Data")]
154 [OdbcDescriptionAttribute ("Input, output, or bidirectional parameter")]
155 [RefreshPropertiesAttribute (RefreshProperties
.All
)]
158 ParameterDirection Direction
{
159 get { return direction; }
160 set { direction = value; }
163 [OdbcDescriptionAttribute ("A design-time property used for strongly typed code generation")]
167 get { return isNullable; }
168 set { isNullable = value; }
171 [DefaultValue (OdbcType
.NChar
)]
172 [OdbcDescriptionAttribute ("The parameter native type")]
173 [RefreshPropertiesAttribute (RefreshProperties
.All
)]
174 [OdbcCategory ("Data")]
175 [DbProviderSpecificTypeProperty (true)]
176 public OdbcType OdbcType
{
177 get { return _typeMap.OdbcType; }
179 if (value == _typeMap
.OdbcType
)
182 _typeMap
= OdbcTypeConverter
.GetTypeMap (value);
186 [OdbcDescription ("DataParameter_ParameterName")]
189 string ParameterName
{
191 set { name = value; }
194 [OdbcDescription ("DbDataParameter_Precision")]
195 [OdbcCategory ("DataCategory_Data")]
197 public byte Precision
{
198 get { return _precision; }
199 set { _precision = value; }
202 [OdbcDescription ("DbDataParameter_Scale")]
203 [OdbcCategory ("DataCategory_Data")]
206 get { return _scale; }
207 set { _scale = value; }
210 [OdbcDescription ("DbDataParameter_Size")]
211 [OdbcCategory ("DataCategory_Data")]
216 set { size = value; }
219 [OdbcDescription ("DataParameter_SourceColumn")]
220 [OdbcCategory ("DataCategory_Data")]
223 string SourceColumn
{
224 get { return sourceColumn; }
225 set { sourceColumn = value; }
228 [OdbcDescription ("DataParameter_SourceVersion")]
229 [OdbcCategory ("DataCategory_Data")]
232 DataRowVersion SourceVersion
{
233 get { return sourceVersion; }
234 set { sourceVersion = value; }
237 [TypeConverter (typeof(StringConverter
))]
238 [OdbcDescription ("DataParameter_Value")]
239 [OdbcCategory ("DataCategory_Data")]
240 [RefreshPropertiesAttribute (RefreshProperties
.All
)]
244 get { return _value; }
245 set { _value = value; }
248 #endregion // Properties
252 internal void Bind (OdbcCommand command
, IntPtr hstmt
, int ParamNum
)
257 // Convert System.Data.ParameterDirection into odbc enum
258 OdbcInputOutputDirection paramdir
= libodbc
.ConvertParameterDirection (this.Direction
);
260 _cbLengthInd
.EnsureAlloc (Marshal
.SizeOf (typeof (int)));
262 len
= (int)OdbcLengthIndicator
.NullData
;
264 len
= GetNativeSize ();
268 Marshal
.WriteInt32 (_cbLengthInd
, len
);
269 ret
= libodbc
.SQLBindParameter (hstmt
, (ushort) ParamNum
, (short) paramdir
,
270 _typeMap
.NativeType
, _typeMap
.SqlType
, Convert
.ToUInt32 (Size
),
271 0, (IntPtr
) _nativeBuffer
, 0, _cbLengthInd
);
273 // Check for error condition
274 if ((ret
!= OdbcReturn
.Success
) && (ret
!= OdbcReturn
.SuccessWithInfo
))
275 throw command
.Connection
.CreateOdbcException (OdbcHandleType
.Stmt
, hstmt
);
279 object ICloneable
.Clone ()
281 throw new NotImplementedException ();
284 public override string ToString ()
286 return ParameterName
;
289 private int GetNativeSize ()
291 TextInfo ti
= CultureInfo
.InvariantCulture
.TextInfo
;
292 Encoding enc
= Encoding
.GetEncoding (ti
.ANSICodePage
);
294 switch (_typeMap
.OdbcType
) {
295 case OdbcType
.Binary
:
296 if (Value
.GetType ().IsArray
&&
297 Value
.GetType ().GetElementType () == typeof (byte))
298 return ( (Array
) Value
).Length
;
300 return Value
.ToString ().Length
;
302 return Marshal
.SizeOf (typeof (byte));
303 case OdbcType
.Double
:
304 return Marshal
.SizeOf (typeof (double));
306 return Marshal
.SizeOf (typeof (float));
308 return Marshal
.SizeOf (typeof (int));
309 case OdbcType
.BigInt
:
310 return Marshal
.SizeOf (typeof (long));
311 case OdbcType
.Decimal
:
312 case OdbcType
.Numeric
:
314 case OdbcType
.SmallInt
:
315 return Marshal
.SizeOf (typeof (Int16
));
316 case OdbcType
.TinyInt
:
317 return Marshal
.SizeOf (typeof (byte));
320 case OdbcType
.VarChar
:
321 return enc
.GetByteCount (Convert
.ToString (Value
)) + 1;
324 case OdbcType
.NVarChar
:
325 // FIXME: Change to unicode
326 return enc
.GetByteCount (Convert
.ToString (Value
)) + 1;
327 case OdbcType
.VarBinary
:
329 if (Value
.GetType ().IsArray
&&
330 Value
.GetType ().GetElementType () == typeof (byte))
331 return ((Array
) Value
).Length
;
332 throw new ArgumentException ("Unsupported Native Type!");
334 case OdbcType
.DateTime
:
335 case OdbcType
.SmallDateTime
:
337 case OdbcType
.Timestamp
:
339 case OdbcType
.UniqueIdentifier
:
340 return Marshal
.SizeOf (typeof (Guid
));
343 if (Value
.GetType ().IsArray
&&
344 Value
.GetType ().GetElementType () == typeof (byte))
345 return ((Array
) Value
).Length
;
347 return Value
.ToString ().Length
;
350 private void AllocateBuffer ()
352 int size
= GetNativeSize ();
354 if (_nativeBuffer
.Size
== size
)
357 _nativeBuffer
.AllocBuffer (size
);
360 internal void CopyValue ()
362 if (_nativeBuffer
.Handle
== IntPtr
.Zero
)
369 TextInfo ti
= CultureInfo
.InvariantCulture
.TextInfo
;
370 Encoding enc
= Encoding
.GetEncoding (ti
.ANSICodePage
);
371 byte [] nativeBytes
, buffer
;
373 switch (_typeMap
.OdbcType
) {
375 Marshal
.WriteByte (_nativeBuffer
, Convert
.ToByte (Value
));
377 case OdbcType
.Double
:
378 Marshal
.StructureToPtr (Convert
.ToDouble (Value
), _nativeBuffer
, false);
381 Marshal
.StructureToPtr (Convert
.ToSingle (Value
), _nativeBuffer
, false);
384 Marshal
.WriteInt32 (_nativeBuffer
, Convert
.ToInt32 (Value
));
386 case OdbcType
.BigInt
:
387 Marshal
.WriteInt64 (_nativeBuffer
, Convert
.ToInt64 (Value
));
389 case OdbcType
.Decimal
:
390 case OdbcType
.Numeric
:
391 // for numeric, the buffer is a packed decimal struct.
392 // ref http://www.it-faq.pl/mskb/181/254.HTM
393 int [] bits
= Decimal
.GetBits (Convert
.ToDecimal (Value
));
394 buffer
= new byte [19]; // ref sqltypes.h
395 buffer
[0] = Precision
;
396 buffer
[1] = (byte) ((bits
[3] & 0x00FF0000) >> 16); // scale
397 buffer
[2] = (byte) ((bits
[3] & 0x80000000) > 0 ? 2 : 1); //sign
398 Buffer
.BlockCopy (bits
, 0, buffer
, 3, 12); // copy data
399 for (int j
= 16; j
< 19; j
++) // pad with 0
401 Marshal
.Copy (buffer
, 0, _nativeBuffer
, 19);
403 case OdbcType
.SmallInt
:
404 Marshal
.WriteInt16 (_nativeBuffer
, Convert
.ToInt16 (Value
));
406 case OdbcType
.TinyInt
:
407 Marshal
.WriteByte (_nativeBuffer
, Convert
.ToByte (Value
));
411 case OdbcType
.VarChar
:
412 buffer
= new byte [GetNativeSize ()];
413 nativeBytes
= enc
.GetBytes (Convert
.ToString (Value
));
414 Array
.Copy (nativeBytes
, 0, buffer
, 0, nativeBytes
.Length
);
415 buffer
[buffer
.Length
-1] = (byte) 0;
416 Marshal
.Copy (buffer
, 0, _nativeBuffer
, buffer
.Length
);
417 Marshal
.WriteInt32 (_cbLengthInd
, -3);
421 case OdbcType
.NVarChar
:
422 // FIXME : change to unicode
423 buffer
= new byte [GetNativeSize ()];
424 nativeBytes
= enc
.GetBytes (Convert
.ToString (Value
));
425 Array
.Copy (nativeBytes
, 0, buffer
, 0, nativeBytes
.Length
);
426 buffer
[buffer
.Length
-1] = (byte) 0;
427 Marshal
.Copy (buffer
, 0, _nativeBuffer
, buffer
.Length
);
428 Marshal
.WriteInt32 (_cbLengthInd
, -3);
430 case OdbcType
.VarBinary
:
432 case OdbcType
.Binary
:
433 if (Value
.GetType ().IsArray
&&
434 Value
.GetType ().GetElementType () == typeof (byte)) {
435 Marshal
.Copy ( (byte []) Value
, 0, _nativeBuffer
, ((byte []) Value
).Length
);
437 throw new ArgumentException ("Unsupported Native Type!");
440 dt
= (DateTime
) Value
;
441 Marshal
.WriteInt16 (_nativeBuffer
, 0, (short) dt
.Year
);
442 Marshal
.WriteInt16 (_nativeBuffer
, 2, (short) dt
.Month
);
443 Marshal
.WriteInt16 (_nativeBuffer
, 4, (short) dt
.Day
);
446 dt
= (DateTime
) Value
;
447 Marshal
.WriteInt16 (_nativeBuffer
, 0, (short) dt
.Hour
);
448 Marshal
.WriteInt16 (_nativeBuffer
, 2, (short) dt
.Minute
);
449 Marshal
.WriteInt16 (_nativeBuffer
, 4, (short) dt
.Second
);
451 case OdbcType
.SmallDateTime
:
452 case OdbcType
.Timestamp
:
453 case OdbcType
.DateTime
:
454 dt
= (DateTime
) Value
;
455 Marshal
.WriteInt16 (_nativeBuffer
, 0, (short) dt
.Year
);
456 Marshal
.WriteInt16 (_nativeBuffer
, 2, (short) dt
.Month
);
457 Marshal
.WriteInt16 (_nativeBuffer
, 4, (short) dt
.Day
);
458 Marshal
.WriteInt16 (_nativeBuffer
, 6, (short) dt
.Hour
);
459 Marshal
.WriteInt16 (_nativeBuffer
, 8, (short) dt
.Minute
);
460 Marshal
.WriteInt16 (_nativeBuffer
, 10, (short) dt
.Second
);
461 Marshal
.WriteInt32 (_nativeBuffer
, 12, (int) (dt
.Ticks
% 10000000) * 100);
463 case OdbcType
.UniqueIdentifier
:
464 throw new NotImplementedException ();
467 if (Value
.GetType ().IsArray
&&
468 Value
.GetType ().GetElementType () == typeof (byte)) {
469 Marshal
.Copy ( (byte []) Value
, 0, _nativeBuffer
, ((byte []) Value
).Length
);
471 throw new ArgumentException ("Unsupported Native Type!");
474 public override bool SourceColumnNullMapping
{
475 get { return false; }
479 public override void ResetDbType ()
481 _typeMap
= OdbcTypeConverter
.GetTypeMap (OdbcType
.NVarChar
);
484 public void ResetOdbcType ()
486 _typeMap
= OdbcTypeConverter
.GetTypeMap (OdbcType
.NVarChar
);