2005-10-08 Sureshkumar T <tsureshkumar@novell.com>
[mono.git] / mcs / class / System.Data / System.Data.Odbc / OdbcParameter.cs
1 //
2 // System.Data.Odbc.OdbcParameter
3 //
4 // Authors:
5 //   Brian Ritchie (brianlritchie@hotmail.com)
6 //   Sureshkumar T <tsureshkumar@novell.com>  2004.
7 //
8 // Copyright (C) Brian Ritchie, 2002
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
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:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
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.
32 //
33
34 using System;
35 using System.Text;
36 using System.Data;
37 using System.Data.Common;
38
39 using System.Runtime.InteropServices;
40 using System.Globalization;
41
42 #if NET_2_0
43 using System.Data.ProviderBase;
44 #endif // NET_2_0
45 using System.ComponentModel;
46
47 namespace System.Data.Odbc
48 {
49         [TypeConverterAttribute (typeof (OdbcParameterConverter))]
50 #if NET_2_0
51         public sealed class OdbcParameter : DbParameterBase, ICloneable
52 #else
53                 public sealed class OdbcParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
54 #endif // NET_2_0
55         {
56                 #region Fields
57
58 #if ONLY_1_1
59                 string name;
60                 ParameterDirection direction;
61                 bool isNullable;
62                 int size;
63                 DataRowVersion sourceVersion;
64                 string sourceColumn;
65                 byte _precision;
66                 byte _scale;
67                 object _value;
68 #endif // ONLY_1_1
69
70                 private OdbcTypeMap _typeMap;
71                 private NativeBuffer _nativeBuffer = new NativeBuffer ();
72                 private NativeBuffer _cbLengthInd;
73                 private OdbcParameterCollection container = null;       
74                 
75                 #endregion
76
77                 #region Constructors
78                 
79                 public OdbcParameter ()
80                 {
81                         _cbLengthInd = new NativeBuffer ();
82                         ParameterName = String.Empty;
83                         IsNullable = true;
84                         SourceColumn = String.Empty;
85                         Direction = ParameterDirection.Input;
86                         _typeMap = OdbcTypeConverter.GetTypeMap (OdbcType.VarChar);
87                 }
88
89                 public OdbcParameter (string name, object value) 
90                         : this ()
91                 {
92                         this.ParameterName = name;
93                         Value = value;
94                         _typeMap = OdbcTypeConverter.InferFromValue (value);
95                         if (value != null && !value.GetType ().IsValueType) {
96                                 Type type = value.GetType ();
97                                 if (type.IsArray)
98                                         Size = type.GetElementType () == typeof (byte) ?
99                                                 ((Array) value).Length : 0;
100                                 else
101                                         Size = value.ToString ().Length;
102                         }
103                 }
104
105                 public OdbcParameter (string name, OdbcType odbcType) 
106                         : this ()
107                 {
108                         this.ParameterName = name;
109                         _typeMap = (OdbcTypeMap) OdbcTypeConverter.GetTypeMap (odbcType);
110                 }
111
112                 public OdbcParameter (string name, OdbcType odbcType, int size)
113                         : this (name, odbcType)
114                 {
115                         this.Size = size;
116                 }
117
118                 public OdbcParameter (string name, OdbcType odbcType, int size, string srcColumn)
119                         : this (name, odbcType, size)
120                 {
121                         this.SourceColumn = srcColumn;
122                 }
123
124                 [EditorBrowsable (EditorBrowsableState.Advanced)]
125                 public OdbcParameter(string name, OdbcType odbcType, int size, 
126                                      ParameterDirection direction, bool isNullable, 
127                                      byte precision, byte scale, string srcColumn, 
128                                      DataRowVersion srcVersion, object value)
129                         : this (name, odbcType, size, srcColumn)
130                 {
131                         this.Direction = direction;
132                         this.IsNullable = isNullable;
133                         this.SourceVersion = srcVersion;
134                 }
135
136                 #endregion
137
138                 #region Properties
139
140                 // Used to ensure that only one collection can contain this
141                 // parameter
142                 internal OdbcParameterCollection Container {
143                         get { return container; }
144                         set { container = value; }
145                 }
146                 
147                 [BrowsableAttribute (false)]
148                 [OdbcDescriptionAttribute ("The parameter generic type")]
149                 [RefreshPropertiesAttribute (RefreshProperties.All)]
150                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
151                 [OdbcCategory ("Data")]
152                 public 
153 #if NET_2_0
154                 override 
155 #endif // NET_2_0
156                 DbType DbType {
157                         get { return _typeMap.DbType; }
158                         set { 
159                                 if (value == _typeMap.DbType)
160                                         return;
161                                 
162                                 _typeMap = OdbcTypeConverter.GetTypeMap (value);
163                         }
164                 }
165                 
166 #if ONLY_1_1
167                 [OdbcCategory ("Data")]
168                 [OdbcDescriptionAttribute ("Input, output, or bidirectional parameter")]  
169                 [DefaultValue (ParameterDirection.Input)]
170                 public ParameterDirection Direction {
171                         get { return direction; }
172                         set { direction = value; }
173                 }
174                 
175                 [BrowsableAttribute (false)]
176                 [OdbcDescriptionAttribute ("A design-time property used for strongly typed code generation")]
177                 [DesignOnlyAttribute (true)]
178                 [EditorBrowsableAttribute (EditorBrowsableState.Advanced)]
179                 [DefaultValue (false)]
180                 public bool IsNullable {
181                         get { return isNullable; }
182                         set { isNullable = value; }
183                 }
184 #endif // ONLY_1_1
185
186
187                 [DefaultValue (OdbcType.NChar)]
188                 [OdbcDescriptionAttribute ("The parameter native type")]
189                 [RefreshPropertiesAttribute (RefreshProperties.All)]
190                 [OdbcCategory ("Data")]
191                 public OdbcType OdbcType {
192                         get { return _typeMap.OdbcType; }
193                         set {
194                                 if (value == OdbcType)
195                                         return;
196
197                                 _typeMap = OdbcTypeConverter.GetTypeMap (value);
198                         }
199                 }
200                 
201 #if ONLY_1_1
202                 [OdbcDescription ("DataParameter_ParameterName")]
203                 [DefaultValue ("")]     
204                 public string ParameterName {
205                         get { return name; }
206                         set { name = value; }
207                 }
208
209                 [OdbcDescription ("DbDataParameter_Precision")]
210                 [OdbcCategory ("DataCategory_Data")]
211                 [DefaultValue (0)]
212                 public byte Precision {
213                         get { return _precision; }
214                         set { _precision = value; }
215                 }
216                 
217                 [OdbcDescription ("DbDataParameter_Scale")]
218                 [OdbcCategory ("DataCategory_Data")]
219                 [DefaultValue (0)]
220                 public byte Scale {
221                         get { return _scale; }
222                         set { _scale = value; }
223                 }
224                 
225                 [OdbcDescription ("DbDataParameter_Size")]
226                 [OdbcCategory ("DataCategory_Data")]
227                 [DefaultValue (0)]
228                 public int Size {
229                         get { return size; }
230                         set { size = value; }
231                 }
232
233                 [OdbcDescription ("DataParameter_SourceColumn")]
234                 [OdbcCategory ("DataCategory_Data")]
235                 [DefaultValue ("")]
236                 public string SourceColumn {
237                         get { return sourceColumn; }
238                         set { sourceColumn = value; }
239                 }
240                 
241                 [OdbcDescription ("DataParameter_SourceVersion")]
242                 [OdbcCategory ("DataCategory_Data")]
243                 [DefaultValue ("Current")]                      
244                 public DataRowVersion SourceVersion {
245                         get { return sourceVersion; }
246                         set { sourceVersion = value; }
247                 }
248
249                 [TypeConverter (typeof(StringConverter))]
250                 [OdbcDescription ("DataParameter_Value")]
251                 [OdbcCategory ("DataCategory_Data")]
252                 [DefaultValue (null)]           
253                 public  object Value {
254                         get { 
255                                 return _value;
256                         }
257                         set { 
258                                 _value = value;
259                         }
260                 }
261
262 #endif // ONLY_1_1
263
264                 #endregion // Properties
265
266                 #region Methods
267
268                 internal void Bind(IntPtr hstmt, int ParamNum) {
269                         OdbcReturn ret;
270                         
271                         // Convert System.Data.ParameterDirection into odbc enum
272                         OdbcInputOutputDirection paramdir = libodbc.ConvertParameterDirection(this.Direction);
273
274                         _cbLengthInd.EnsureAlloc (Marshal.SizeOf (typeof (int)));
275                         Marshal.WriteInt32 (_cbLengthInd, GetNativeSize ());
276                         AllocateBuffer ();
277                         ret = libodbc.SQLBindParameter(hstmt, (ushort) ParamNum, (short) paramdir,
278                                                        _typeMap.NativeType, _typeMap.SqlType, Convert.ToUInt32(Size),
279                                                        0, (IntPtr) _nativeBuffer, 0, _cbLengthInd);
280
281                         // Check for error condition
282                         if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
283                                 throw new OdbcException(new OdbcError("SQLBindParam", OdbcHandleType.Stmt, hstmt));
284                 }
285
286                 [MonoTODO]
287                 object ICloneable.Clone ()
288                 {
289                         throw new NotImplementedException ();
290                 }
291
292                 public override string ToString ()
293                 {
294                         return ParameterName;
295                 }
296                 
297                 private int GetNativeSize ()
298                 {
299                         TextInfo ti = CultureInfo.InvariantCulture.TextInfo;
300                         Encoding enc = Encoding.GetEncoding (ti.ANSICodePage);
301
302                         switch (_typeMap.OdbcType) {
303                         case OdbcType.Binary:
304                                 if (Value.GetType ().IsArray &&
305                                     Value.GetType ().GetElementType () == typeof (byte))
306                                         return ( (Array) Value).Length;
307                                 else
308                                         return Value.ToString ().Length;
309                         case OdbcType.Bit:
310                                 return Marshal.SizeOf (typeof  (byte));
311                         case OdbcType.Double:
312                                 return Marshal.SizeOf (typeof (double));
313                         case OdbcType.Real:
314                                 return Marshal.SizeOf (typeof (float));
315                         case OdbcType.Int:
316                                 return Marshal.SizeOf (typeof (int));
317                         case OdbcType.BigInt:
318                                 return Marshal.SizeOf (typeof  (long));
319                         case OdbcType.Numeric:
320                                 return Value.ToString ().Length;
321                         case OdbcType.SmallInt:
322                                 return Marshal.SizeOf (typeof  (Int16));
323                         case OdbcType.TinyInt:
324                                 return Marshal.SizeOf (typeof  (byte));
325                         case OdbcType.Char:
326                         case OdbcType.Text:
327                         case OdbcType.VarChar:
328                                 return enc.GetByteCount (Convert.ToString (Value)) + 1;
329                         case OdbcType.NChar:
330                         case OdbcType.NText:
331                         case OdbcType.NVarChar:
332                                 // FIXME: Change to unicode
333                                 return enc.GetByteCount (Convert.ToString (Value)) + 1;
334                         case OdbcType.VarBinary:
335                         case OdbcType.Image:
336                                 if (Value.GetType ().IsArray &&
337                                     Value.GetType ().GetElementType () == typeof (byte))
338                                         return ( (Array) Value).Length;
339                                 throw new ArgumentException ("Unsupported Native Type!");
340                         case OdbcType.Date:
341                         case OdbcType.DateTime:
342                         case OdbcType.SmallDateTime:
343                         case OdbcType.Time:
344                         case OdbcType.Timestamp:
345                                 return 18;
346                         case OdbcType.UniqueIdentifier:
347                                 return Marshal.SizeOf (typeof (Guid));
348                         }
349
350                         if (Value.GetType ().IsArray &&
351                             Value.GetType ().GetElementType () == typeof (byte))
352                                 return ( (Array) Value).Length;
353                         
354                         return Value.ToString ().Length;
355                 }
356
357                 private void AllocateBuffer ()
358                 {
359                         int size = GetNativeSize ();
360
361                         if (_nativeBuffer.Size == size)
362                                 return;
363
364                         _nativeBuffer.AllocBuffer (size);
365                 }
366
367                 internal void CopyValue ()
368                 {
369                         if (_nativeBuffer.Handle == IntPtr.Zero)
370                                 return;
371
372                         DateTime dt;
373                         TextInfo ti = CultureInfo.InvariantCulture.TextInfo;
374                         Encoding enc = Encoding.GetEncoding (ti.ANSICodePage);
375                         byte [] nativeBytes, buffer;
376
377                         switch (_typeMap.OdbcType) {
378                         case OdbcType.Binary:
379                                 throw new NotImplementedException ();
380                         case OdbcType.Bit:
381                                 Marshal.WriteByte (_nativeBuffer, Convert.ToByte (Value));
382                                 return;
383                         case OdbcType.Double:
384                                 Marshal.StructureToPtr (Convert.ToDouble (Value), _nativeBuffer, false);
385                                 return;
386                         case OdbcType.Real:
387                                 Marshal.StructureToPtr (Convert.ToSingle (Value), _nativeBuffer, false);
388                                 return;
389                         case OdbcType.Int:
390                                 Marshal.WriteInt32 (_nativeBuffer, Convert.ToInt32 (Value));
391                                 return;
392                         case OdbcType.BigInt:
393                                 Marshal.WriteInt64 (_nativeBuffer, Convert.ToInt64 (Value));
394                                 return;
395                         case OdbcType.Numeric:
396                                 throw new NotImplementedException ();
397                         case OdbcType.SmallInt:
398                                 Marshal.WriteInt16 (_nativeBuffer, Convert.ToInt16 (Value));
399                                 return;
400                         case OdbcType.TinyInt:
401                                 Marshal.WriteByte (_nativeBuffer, Convert.ToByte (Value));
402                                 return;
403                         case OdbcType.Char:
404                         case OdbcType.Text:
405                         case OdbcType.VarChar:
406                                 buffer = new byte [GetNativeSize ()];
407                                 nativeBytes = enc.GetBytes (Convert.ToString (Value));
408                                 Array.Copy (nativeBytes, 0, buffer, 0, nativeBytes.Length);
409                                 buffer [buffer.Length-1] = (byte) 0;
410                                 Marshal.Copy (buffer, 0, _nativeBuffer, buffer.Length);
411                                 Marshal.WriteInt32 (_cbLengthInd, -3);
412                                 return;
413                         case OdbcType.NChar:
414                         case OdbcType.NText:
415                         case OdbcType.NVarChar:
416                                 // FIXME : change to unicode
417                                 buffer = new byte [GetNativeSize ()];
418                                 nativeBytes = enc.GetBytes (Convert.ToString (Value));
419                                 Array.Copy (nativeBytes, 0, buffer, 0, nativeBytes.Length);
420                                 buffer [buffer.Length-1] = (byte) 0;
421                                 Marshal.Copy (buffer, 0, _nativeBuffer, buffer.Length);
422                                 Marshal.WriteInt32 (_cbLengthInd, -3);
423                                 return;
424                         case OdbcType.VarBinary:
425                         case OdbcType.Image:
426                                 if (Value.GetType ().IsArray &&
427                                     Value.GetType ().GetElementType () == typeof (byte)) {
428                                         Marshal.Copy ( (byte []) Value, 0, _nativeBuffer, ((byte []) Value).Length);
429                                 }else
430                                         throw new ArgumentException ("Unsupported Native Type!");
431                                 return;
432                         case OdbcType.Date:
433                                 dt = (DateTime) Value;
434                                 Marshal.WriteInt16 (_nativeBuffer, 0, (short) dt.Year);
435                                 Marshal.WriteInt16 (_nativeBuffer, 2, (short) dt.Month);
436                                 Marshal.WriteInt16 (_nativeBuffer, 4, (short) dt.Day);
437                                 return;
438                         case OdbcType.Time:
439                                 dt = (DateTime) Value;
440                                 Marshal.WriteInt16 (_nativeBuffer, 0, (short) dt.Hour);
441                                 Marshal.WriteInt16 (_nativeBuffer, 2, (short) dt.Minute);
442                                 Marshal.WriteInt16 (_nativeBuffer, 4, (short) dt.Second);
443                                 return;
444                         case OdbcType.SmallDateTime:
445                         case OdbcType.Timestamp:
446                         case OdbcType.DateTime:
447                                 dt = (DateTime) Value;
448                                 Marshal.WriteInt16 (_nativeBuffer, 0, (short) dt.Year);
449                                 Marshal.WriteInt16 (_nativeBuffer, 2, (short) dt.Month);
450                                 Marshal.WriteInt16 (_nativeBuffer, 4, (short) dt.Day);
451                                 Marshal.WriteInt16 (_nativeBuffer, 6, (short) dt.Hour);
452                                 Marshal.WriteInt16 (_nativeBuffer, 8, (short) dt.Minute);
453                                 Marshal.WriteInt16 (_nativeBuffer, 10, (short) dt.Second);
454                                 Marshal.WriteInt32 (_nativeBuffer, 12, (int) (dt.Ticks % 10000000) * 100);
455                                 return;
456                         case OdbcType.UniqueIdentifier:
457                                 throw new NotImplementedException ();
458                         }
459
460                         if (Value.GetType ().IsArray &&
461                             Value.GetType ().GetElementType () == typeof (byte)) {
462                                 Marshal.Copy ( (byte []) Value, 0, _nativeBuffer, ((byte []) Value).Length);
463                         }else
464                                 throw new ArgumentException ("Unsupported Native Type!");
465                 }
466
467 #if NET_2_0
468                 [MonoTODO]
469                 public override void PropertyChanging () 
470                 {
471                 }
472                 
473                 [MonoTODO]
474                 protected override byte ValuePrecision (object value) 
475                 {
476                         throw new NotImplementedException ();
477                 }
478
479                 [MonoTODO]
480                 protected override byte ValueScale (object value)
481                 {
482                         throw new NotImplementedException ();
483                 }
484
485                 [MonoTODO]
486                 protected override int ValueSize (object value)
487                 {
488                         throw new NotImplementedException ();
489                 }
490
491                 [MonoTODO]
492                 public override void ResetDbType () 
493                 {
494                         throw new NotImplementedException ();
495                 }
496
497 #endif // NET_2_0
498                 #endregion
499         }
500 }