Applied patch from: David Pickens <dsp@rci.rutgers.edu>
[mono.git] / mcs / class / System.Data.OracleClient / System.Data.OracleClient / OracleParameter.cs
1 // 
2 // OracleParameter.cs
3 //
4 // Part of the Mono class libraries at
5 // mcs/class/System.Data.OracleClient/System.Data.OracleClient
6 //
7 // Assembly: System.Data.OracleClient.dll
8 // Namespace: System.Data.OracleClient
9 //
10 // Authors: 
11 //    Tim Coleman <tim@timcoleman.com>
12 //
13 // Copyright (C) Tim Coleman , 2003
14 //
15 // Licensed under the MIT/X11 License.
16 //
17
18 using System;
19 using System.Collections;
20 using System.ComponentModel;
21 using System.Data;
22 using System.Data.OracleClient.Oci;
23 using System.Runtime.InteropServices;
24
25 namespace System.Data.OracleClient {
26         public sealed class OracleParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
27         {
28                 #region Fields
29
30                 string name;
31                 OracleType oracleType = OracleType.VarChar;
32                 OciDataType ociType;
33                 int size;
34                 ParameterDirection direction = ParameterDirection.Input;
35                 bool isNullable;
36                 byte precision;
37                 byte scale;
38                 string srcColumn;
39                 DataRowVersion srcVersion;
40                 DbType dbType = DbType.AnsiString;
41                 int offset = 0;
42                 bool sizeSet = false;
43                 object value = null;
44
45                 OracleParameterCollection container = null;
46                 OciBindHandle bindHandle;
47
48                 #endregion // Fields
49
50                 #region Constructors
51
52                 public OracleParameter ()
53                         : this (String.Empty, OracleType.VarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
54                 {
55                 }
56
57                 public OracleParameter (string name, object value)
58                 {
59                         this.name = name;
60                         this.value = value;
61                         SourceVersion = DataRowVersion.Current;
62                         InferOracleType (value);
63                 }
64
65                 public OracleParameter (string name, OracleType dataType)
66                         : this (name, dataType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
67                 {
68                 }
69
70                 public OracleParameter (string name, OracleType dataType, int size)
71                         : this (name, dataType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
72                 {
73                 }
74
75                 public OracleParameter (string name, OracleType dataType, int size, string srcColumn)
76                         : this (name, dataType, size, ParameterDirection.Input, false, 0, 0, srcColumn, DataRowVersion.Current, null)
77                 {
78                 }
79
80                 public OracleParameter (string name, OracleType dataType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string srcColumn, DataRowVersion srcVersion, object value)
81                 {
82                         this.name = name;
83                         this.size = size;
84                         this.value = value;
85
86                         OracleType = dataType;
87                         Direction = direction;
88                         SourceColumn = srcColumn;
89                         SourceVersion = srcVersion;
90                 }
91
92                 #endregion // Constructors
93
94                 #region Properties
95
96                 internal OracleParameterCollection Container {
97                         get { return container; }
98                         set { container = value; }
99                 }
100
101                 public DbType DbType {
102                         get { return dbType; }
103                         set { SetDbType (value); }
104                 }
105
106                 public ParameterDirection Direction {
107                         get { return direction; }
108                         set { direction = value; }
109                 }
110
111                 public bool IsNullable {
112                         get { return isNullable; }
113                         set { isNullable = value; }
114                 }
115
116                 public int Offset {
117                         get { return offset; }
118                         set { offset = value; }
119                 }
120
121                 public OracleType OracleType {
122                         get { return oracleType; }
123                         set { SetOracleType (value); }
124                 }
125                 
126                 public string ParameterName {
127                         get { return name; }
128                         set { name = value; }
129                 }
130
131                 public byte Precision {
132                         get { return precision; }
133                         set { /* NO EFFECT*/ }
134                 }
135
136                 public byte Scale {
137                         get { return scale; }
138                         set { /* NO EFFECT*/ }
139                 }
140
141                 public int Size {
142                         get { return size; }
143                         set { 
144                                 sizeSet = true;
145                                 size = value; 
146                         }
147                 }
148
149                 public string SourceColumn {
150                         get { return srcColumn; }
151                         set { srcColumn = value; }
152                 }
153
154                 public DataRowVersion SourceVersion {
155                         get { return srcVersion; }
156                         set { srcVersion = value; }
157                 }
158
159                 public object Value {
160                         get { return this.value; }
161                         set { this.value = value; }
162                 }
163
164                 #endregion // Properties
165
166                 #region Methods
167
168                 [DllImport ("oci")]
169                 static extern int OCIBindByName (IntPtr stmtp,
170                                                 out IntPtr bindpp,
171                                                 IntPtr errhp,
172                                                 string placeholder,
173                                                 int placeh_len,
174                                                 IntPtr valuep,
175                                                 int value_sz,
176                                                 [MarshalAs (UnmanagedType.U2)] OciDataType dty,
177                                                 int indp,
178                                                 IntPtr alenp,
179                                                 IntPtr rcodep,
180                                                 uint maxarr_len,
181                                                 IntPtr curelp,
182                                                 uint mode);
183
184
185                 private void AssertSizeIsSet ()
186                 {
187                         if (!sizeSet)
188                                 throw new Exception ("Size must be set.");
189                 }
190
191                 internal void Bind (OciStatementHandle statement, OracleConnection connection)
192                 {
193                         if (bindHandle == null)
194                                 bindHandle = new OciBindHandle ((OciHandle) statement);
195
196                         IntPtr tmpHandle = bindHandle.Handle;
197
198                         if (Direction != ParameterDirection.Input)
199                                 AssertSizeIsSet ();
200                         if (!sizeSet)
201                                 size = InferSize ();
202
203                         int status = 0;
204                         int indicator = 0;
205                         OciDataType bindType = ociType;
206                         IntPtr bindValue = IntPtr.Zero;
207                         int bindSize = size;
208
209                         if (value == DBNull.Value)
210                                 indicator = -1;
211                         else {
212                                 bindType = OciDataType.VarChar2; // FIXME
213                                 bindValue = Marshal.StringToHGlobalAnsi (value.ToString ());
214                                 bindSize = value.ToString ().Length;
215                         }
216
217                         status = OCIBindByName (statement,
218                                                 out tmpHandle,
219                                                 connection.ErrorHandle,
220                                                 ParameterName,
221                                                 ParameterName.Length,
222                                                 bindValue,
223                                                 bindSize,
224                                                 bindType,
225                                                 indicator,
226                                                 IntPtr.Zero,
227                                                 IntPtr.Zero,
228                                                 0,
229                                                 IntPtr.Zero,
230                                                 0);
231
232                         if (status != 0) {
233                                 OciErrorInfo info = connection.ErrorHandle.HandleError ();
234                                 throw new OracleException (info.ErrorCode, info.ErrorMessage);
235                         }
236
237                         bindHandle.SetHandle (tmpHandle);
238                 }
239
240                 [MonoTODO]
241                 object ICloneable.Clone ()
242                 {
243                         throw new NotImplementedException ();
244                 }
245
246                 private void InferOracleType (object value)
247                 {
248                         Type type = value.GetType ();
249                         string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
250                         switch (type.FullName) {
251                         case "System.Int64":
252                                 SetOracleType (OracleType.Number);
253                                 break;
254                         case "System.Boolean":
255                         case "System.Byte":
256                                 SetOracleType (OracleType.Byte);
257                                 break;
258                         case "System.String":
259                                 SetOracleType (OracleType.VarChar);
260                                 break;
261                         case "System.DataType":
262                                 SetOracleType (OracleType.DateTime);
263                                 break;
264                         case "System.Decimal":
265                                 SetOracleType (OracleType.Number);
266                                 //scale = ((decimal) value).Scale;
267                                 break;
268                         case "System.Double":
269                                 SetOracleType (OracleType.Double);
270                                 break;
271                         case "System.Byte[]":
272                         case "System.Guid":
273                                 SetOracleType (OracleType.Raw);
274                                 break;
275                         case "System.Int32":
276                                 SetOracleType (OracleType.Int32);
277                                 break;
278                         case "System.Single":
279                                 SetOracleType (OracleType.Float);
280                                 break;
281                         case "System.Int16":
282                                 SetOracleType (OracleType.Int16);
283                                 break;
284                         default:
285                                 throw new ArgumentException (exception);
286                         }
287                 }
288
289                 [MonoTODO ("different size depending on type.")]
290                 private int InferSize ()
291                 {
292                         return value.ToString ().Length;
293                 }
294
295                 public void SetDbType (DbType type)
296                 {
297                         string exception = String.Format ("No mapping exists from DbType {0} to a known OracleType.", type);
298                         switch (type) {
299                         case DbType.AnsiString:
300                                 oracleType = OracleType.VarChar;
301                                 ociType = OciDataType.VarChar;
302                                 break;
303                         case DbType.AnsiStringFixedLength:
304                                 oracleType = OracleType.Char;
305                                 ociType = OciDataType.Char;
306                                 break;
307                         case DbType.Binary:
308                         case DbType.Guid:
309                                 oracleType = OracleType.Raw;
310                                 ociType = OciDataType.Raw;
311                                 break;
312                         case DbType.Boolean:
313                         case DbType.Byte:
314                                 oracleType = OracleType.Byte;
315                                 ociType = OciDataType.Integer;
316                                 break;
317                         case DbType.Currency:
318                         case DbType.Decimal:
319                         case DbType.Int64:
320                                 oracleType = OracleType.Number;
321                                 ociType = OciDataType.Number;
322                                 break;
323                         case DbType.Date:
324                         case DbType.DateTime:
325                         case DbType.Time:
326                                 oracleType = OracleType.DateTime;
327                                 ociType = OciDataType.Char;
328                                 break;
329                         case DbType.Double:
330                                 oracleType = OracleType.Double;
331                                 ociType = OciDataType.Float;
332                                 break;
333                         case DbType.Int16:
334                                 oracleType = OracleType.Int16;
335                                 ociType = OciDataType.Integer;
336                                 break;
337                         case DbType.Int32:
338                                 oracleType = OracleType.Int32;
339                                 ociType = OciDataType.Integer;
340                                 break;
341                         case DbType.Object:
342                                 oracleType = OracleType.Blob;
343                                 ociType = OciDataType.Blob;
344                                 break;
345                         case DbType.Single:
346                                 oracleType = OracleType.Float;
347                                 ociType = OciDataType.Float;
348                                 break;
349                         case DbType.String:
350                                 oracleType = OracleType.NVarChar;
351                                 ociType = OciDataType.VarChar;
352                                 break;
353                         case DbType.StringFixedLength:
354                                 oracleType = OracleType.NChar;
355                                 ociType = OciDataType.Char;
356                                 break;
357                         default:
358                                 throw new ArgumentException (exception);
359                         }
360                         dbType = type;
361
362                 }
363
364                 public void SetOracleType (OracleType type)
365                 {
366                         string exception = String.Format ("No mapping exists from OracleType {0} to a known DbType.", type);
367                         switch (type) {
368                         case OracleType.BFile:
369                         case OracleType.Blob:
370                         case OracleType.LongRaw:
371                         case OracleType.Raw:
372                                 dbType = DbType.Binary;
373                                 ociType = OciDataType.Raw;
374                                 break;
375                         case OracleType.Byte:
376                                 dbType = DbType.Byte;
377                                 ociType = OciDataType.Integer;
378                                 break;
379                         case OracleType.Char:
380                                 dbType = DbType.AnsiStringFixedLength;
381                                 ociType = OciDataType.Char;
382                                 break;
383                         case OracleType.Clob:
384                         case OracleType.LongVarChar:
385                         case OracleType.RowId:
386                         case OracleType.VarChar:
387                                 dbType = DbType.AnsiString;
388                                 ociType = OciDataType.VarChar;
389                                 break;
390                         case OracleType.Cursor:
391                         case OracleType.IntervalDayToSecond:
392                                 dbType = DbType.Object;
393                                 ociType = OciDataType.Blob;
394                                 break;
395                         case OracleType.DateTime:
396                         case OracleType.Timestamp:
397                         case OracleType.TimestampLocal:
398                         case OracleType.TimestampWithTZ:
399                                 dbType = DbType.DateTime;
400                                 ociType = OciDataType.Char;
401                                 break;
402                         case OracleType.Double:
403                                 dbType = DbType.Double;
404                                 ociType = OciDataType.Float;
405                                 break;
406                         case OracleType.Float:
407                                 dbType = DbType.Single;
408                                 ociType = OciDataType.Float;
409                                 break;
410                         case OracleType.Int16:
411                                 dbType = DbType.Int16;
412                                 ociType = OciDataType.Integer;
413                                 break;
414                         case OracleType.Int32:
415                         case OracleType.IntervalYearToMonth:
416                                 dbType = DbType.Int32;
417                                 ociType = OciDataType.Integer;
418                                 break;
419                         case OracleType.NChar:
420                                 dbType = DbType.StringFixedLength;
421                                 ociType = OciDataType.Char;
422                                 break;
423                         case OracleType.NClob:
424                         case OracleType.NVarChar:
425                                 dbType = DbType.String;
426                                 ociType = OciDataType.VarChar;
427                                 break;
428                         case OracleType.Number:
429                                 dbType = DbType.VarNumeric;
430                                 ociType = OciDataType.Number;
431                                 break;
432                         case OracleType.SByte:
433                                 dbType = DbType.SByte;
434                                 ociType = OciDataType.Integer;
435                                 break;
436                         case OracleType.UInt16:
437                                 dbType = DbType.UInt16;
438                                 ociType = OciDataType.Integer;
439                                 break;
440                         case OracleType.UInt32:
441                                 dbType = DbType.UInt32;
442                                 ociType = OciDataType.Integer;
443                                 break;
444                         default:
445                                 throw new ArgumentException (exception);
446                         }
447
448                         oracleType = type;
449                 }
450
451                 public override string ToString ()
452                 {
453                         return ParameterName;
454                 }
455
456                 #endregion // Methods
457         }
458 }