2005-05-31 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.Data;
36 using System.Data.Common;
37 #if NET_2_0
38 using System.Data.ProviderBase;
39 #endif // NET_2_0
40 using System.ComponentModel;
41
42 namespace System.Data.Odbc
43 {
44         [TypeConverterAttribute (typeof (OdbcParameterConverter))]
45 #if NET_2_0
46         public sealed class OdbcParameter : DbParameterBase, ICloneable
47 #else
48         public sealed class OdbcParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
49 #endif // NET_2_0
50         {
51                 #region Fields
52
53 #if ONLY_1_1
54                 string name;
55                 ParameterDirection direction;
56                 bool isNullable;
57                 int size;
58                 byte precision;
59                 byte scale;
60                 object paramValue;
61                 DataRowVersion sourceVersion;
62                 string sourceColumn;
63 #endif // ONLY_1_1
64                 OdbcType odbcType = OdbcType.NVarChar;
65                 DbType dbType = DbType.String;
66                 OdbcParameterCollection container = null;       
67                 
68                 // Buffers for parameter value based on type. Currently I've only optimized 
69                 // for int parameters and everything else is just converted to a string.
70                 private bool bufferIsSet;
71                 int intbuf;
72                 byte[] buffer;
73
74                 #endregion
75
76                 #region Constructors
77                 
78                 public OdbcParameter ()
79                 {
80                         ParameterName = String.Empty;
81                         Value = null;
82                         Size = 0;
83                         IsNullable = true;
84                         Precision = 0;
85                         Scale = 0;
86                         SourceColumn = String.Empty;
87                 }
88
89                 public OdbcParameter (string name, object value) 
90                         : this ()
91                 {
92                         this.ParameterName = name;
93                         this.Value = value;
94                         
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                 }
106
107                 public OdbcParameter (string name, OdbcType dataType) 
108                         : this ()
109                 {
110                         this.ParameterName = name;
111                         OdbcType = dataType;
112                 }
113
114                 public OdbcParameter (string name, OdbcType dataType, int size)
115                         : this (name, dataType)
116                 {
117                         this.Size = size;
118                 }
119
120                 public OdbcParameter (string name, OdbcType dataType, int size, string srcColumn)
121                         : this (name, dataType, size)
122                 {
123                         this.SourceColumn = srcColumn;
124                 }
125
126                 [EditorBrowsable (EditorBrowsableState.Advanced)]
127                 public OdbcParameter(string name, OdbcType dataType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string srcColumn, DataRowVersion srcVersion, object value)
128                         : this (name, dataType, size, srcColumn)
129                 {
130                         this.Direction = direction;
131                         this.IsNullable = isNullable;
132                         this.Precision = precision;
133                         this.Scale = scale;
134                         this.SourceVersion = srcVersion;
135                         this.Value = value;
136                 }
137
138                 #endregion
139
140                 #region Properties
141
142                 // Used to ensure that only one collection can contain this
143                 // parameter
144                 internal OdbcParameterCollection Container {
145                         get { return container; }
146                         set { container = value; }
147                 }
148                 
149                 [BrowsableAttribute (false)]
150                 [OdbcDescriptionAttribute ("The parameter generic type")]
151                 [RefreshPropertiesAttribute (RefreshProperties.All)]
152                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
153                 [OdbcCategory ("Data")]
154                 public 
155 #if NET_2_0
156                 override 
157 #endif // NET_2_0
158                 DbType DbType {
159                         get { return dbType; }
160                         set { 
161                                 dbType = value;
162                         }
163                 }
164                 
165 #if ONLY_1_1
166                 [OdbcCategory ("Data")]
167                 [OdbcDescriptionAttribute ("Input, output, or bidirectional parameter")]  
168                 [DefaultValue (ParameterDirection.Input)]
169                 public ParameterDirection Direction {
170                         get { return direction; }
171                         set { direction = value; }
172                 }
173                 
174                 [BrowsableAttribute (false)]
175                 [OdbcDescriptionAttribute ("A design-time property used for strongly typed code generation")]
176                 [DesignOnlyAttribute (true)]
177                 [EditorBrowsableAttribute (EditorBrowsableState.Advanced)]
178                 [DefaultValue (false)]
179                 public bool IsNullable {
180                         get { return isNullable; }\r
181                         set { isNullable = value; }\r
182                 }
183 #endif // ONLY_1_1
184
185
186                 [DefaultValue (OdbcType.NChar)]
187                 [OdbcDescriptionAttribute ("The parameter native type")]
188                 [RefreshPropertiesAttribute (RefreshProperties.All)]
189                 [OdbcCategory ("Data")]
190                 public OdbcType OdbcType {
191                         get { return odbcType; }
192                         set {
193                                 odbcType = value;
194                         }
195                 }
196                 
197 #if ONLY_1_1
198                 [OdbcDescription ("DataParameter_ParameterName")]
199                 [DefaultValue ("")]     
200                 public string ParameterName {
201                         get { return name; }
202                         set { name = value; }
203                 }
204
205                 [OdbcDescription ("DbDataParameter_Precision")]
206                 [OdbcCategory ("DataCategory_Data")]
207                 [DefaultValue (0)]
208                 public byte Precision {
209                         get { return precision; }
210                         set { precision = value; }
211                 }
212                 
213                 [OdbcDescription ("DbDataParameter_Scale")]
214                 [OdbcCategory ("DataCategory_Data")]
215                 [DefaultValue (0)]
216                 public byte Scale {
217                         get { return scale; }
218                         set { scale = value; }
219                 }
220                 
221                 [OdbcDescription ("DbDataParameter_Size")]
222                 [OdbcCategory ("DataCategory_Data")]
223                 [DefaultValue (0)]
224                 public int Size {
225                         get { return size; }
226                         set { size = value; }
227                 }
228
229                 [OdbcDescription ("DataParameter_SourceColumn")]
230                 [OdbcCategory ("DataCategory_Data")]
231                 [DefaultValue ("")]
232                 public string SourceColumn {
233                         get { return sourceColumn; }
234                         set { sourceColumn = value; }
235                 }
236                 
237                 [OdbcDescription ("DataParameter_SourceVersion")]
238                 [OdbcCategory ("DataCategory_Data")]
239                 [DefaultValue (512)]                    
240                 public DataRowVersion SourceVersion {
241                         get { return sourceVersion; }
242                         set { sourceVersion = value; }
243                 }
244
245                 [TypeConverter (typeof(StringConverter))]
246                 [OdbcDescription ("DataParameter_Value")]
247                 [OdbcCategory ("DataCategory_Data")]
248                 [DefaultValue (null)]           
249                 public object Value {
250                         get { 
251                                 return paramValue;
252                         }
253                         set { 
254                                 paramValue = value;
255                                 bufferIsSet = false;
256                         }
257                 }
258 #endif // ONLY_1_1
259
260 #if NET_2_0
261                 [TypeConverter (typeof(StringConverter))]
262                 [OdbcDescription ("DataParameter_Value")]
263                 [OdbcCategory ("DataCategory_Data")]
264                 [DefaultValue (null)]           
265                 public override object Value {
266                         get { 
267                                 return base.Value;
268                         }
269                         set { 
270                                 base.Value = value;
271                                 bufferIsSet = false;
272                         }
273                 }
274
275 #endif // NET_2_0
276
277
278                 #endregion // Properties
279
280                 #region Methods\r
281 \r
282                 internal void Bind(IntPtr hstmt, int ParamNum) {\r
283                         OdbcReturn ret;\r
284                         // Set up the buffer if we haven't done so yet\r
285                         if (!bufferIsSet)\r
286                                 setBuffer();\r
287 \r
288                         // Convert System.Data.ParameterDirection into odbc enum\r
289                         OdbcInputOutputDirection paramdir = libodbc.ConvertParameterDirection(this.Direction);
290
291                         SQL_C_TYPE ctype = OdbcTypeConverter.ConvertToSqlCType (odbcType);
292                         SQL_TYPE   sqltype = OdbcTypeConverter.ConvertToSqlType (odbcType);
293                         
294                         // Bind parameter based on type
295                         int ind = -3;
296                         if (odbcType == OdbcType.Int)
297                                 ret = libodbc.SQLBindParameter(hstmt, (ushort)ParamNum, (short)paramdir,
298                                                                ctype, sqltype, Convert.ToUInt32(Size),
299                                                                0, ref intbuf, 0, ref ind);
300                         else
301                                 ret = libodbc.SQLBindParameter(hstmt, (ushort)ParamNum, (short)paramdir,
302                                                                ctype, sqltype, Convert.ToUInt32(Size),
303                                                                0, buffer, buffer.Length, ref ind);
304                         // Check for error condition\r
305                         if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))\r
306                                 throw new OdbcException(new OdbcError("SQLBindParam", OdbcHandleType.Stmt, hstmt));\r
307                 }\r
308 \r
309                 private void setBuffer() {\r
310                         // Load buffer with new value
311                         if (odbcType == OdbcType.Int)
312                                 intbuf = Value == null ? new int () : (int) Value;
313                         else if (odbcType == OdbcType.Numeric
314                                  || odbcType == OdbcType.Decimal) {
315                                 // for numeric, the buffer is a packed decimal struct.
316                                 // ref http://www.it-faq.pl/mskb/181/254.HTM
317                                 if (Value == null)
318                                         Value = (decimal) 0;
319                                 int [] bits = Decimal.GetBits (Convert.ToDecimal (Value));
320                                 buffer = new byte [19]; // ref sqltypes.h
321
322                                 buffer [0] = Precision;
323                                 buffer [1] = (byte) ((bits [3] & 0x00FF0000) >> 16); // scale
324                                 buffer [2] = (byte) ((bits [3] & 0x80000000) > 0 ? 2 : 1); //sign
325                                 Buffer.BlockCopy (bits, 0, buffer, 3, 12); // copy data
326                                 for (int j = 16; j < 19; j++) // pad with 0
327                                         buffer [j] = 0;
328                         } else {\r
329                                 string paramValueString = Value.ToString();\r
330                                 // Treat everything else as a string\r
331                                 // Init string buffer\r
332                                  if (Value is String)
333                                         paramValueString = "\'"+paramValueString+"\'";
334
335                                  int minSize = Size;
336                                  minSize = Size > 20 ? Size : 20;
337                                  if (Value is String)
338                                          minSize += 2; // for enclosing apos
339                                  if (buffer == null || buffer.Length < minSize)
340                                          buffer = new byte[minSize];
341                                  else
342                                          buffer.Initialize();
343                                  
344                                  // Convert value into string and store into buffer
345                                  minSize = paramValueString.Length < minSize ? paramValueString.Length : minSize;
346                                  System.Text.Encoding.ASCII.GetBytes(paramValueString, 0, minSize, buffer, 0);\r
347                         }\r
348                         bufferIsSet = true;\r
349                 }\r
350 \r
351                 [MonoTODO]
352                 object ICloneable.Clone ()
353                 {
354                         throw new NotImplementedException ();
355                 }
356
357                 public override string ToString ()
358                 {
359                         return ParameterName;
360                 }
361
362 #if NET_2_0
363                 [MonoTODO]
364                 public override void PropertyChanging () 
365                 {
366                         throw new NotImplementedException ();
367                 }
368                 
369                 [MonoTODO]
370                 protected override byte ValuePrecision (object value) 
371                 {
372                         throw new NotImplementedException ();
373                 }
374
375                 [MonoTODO]
376                 protected override byte ValueScale (object value)
377                 {
378                         throw new NotImplementedException ();
379                 }
380
381                 [MonoTODO]
382                 protected override int ValueSize (object value)
383                 {
384                         throw new NotImplementedException ();
385                 }
386
387                 [MonoTODO]
388                 public override void ResetDbType () 
389                 {
390                         throw new NotImplementedException ();
391                 }
392
393 #endif // NET_2_0
394                 #endregion
395         }
396 }