2005-09-08 Peter Dennis Bartok <pbartok@novell.com>
[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 //    Daniel Moragn <danielmorgan@verizon.net>
13 //    Hubert FONGARNAND <informatique.internet@fiducial.fr>
14 //
15 // Copyright (C) Tim Coleman , 2003
16 // Copyright (C) Daniel Morgan, 2005
17 // Copyright (C) Hubert FONGARNAND, 2005
18 //
19 // Licensed under the MIT/X11 License.
20 //
21
22 using System;
23 using System.Collections;
24 using System.ComponentModel;
25 using System.Data;
26 using System.Data.OracleClient.Oci;
27 using System.Globalization;
28 using System.Runtime.InteropServices;
29 using System.Text;
30
31 namespace System.Data.OracleClient {
32         [TypeConverter (typeof(OracleParameter.OracleParameterConverter))]
33         public sealed class OracleParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
34         {
35                 #region Fields
36
37                 string name;
38                 OracleType oracleType = OracleType.VarChar;
39                 OciDataType ociType;
40                 int size;
41                 ParameterDirection direction = ParameterDirection.Input;
42                 bool isNullable;
43                 byte precision;
44                 byte scale;
45                 string srcColumn;
46                 DataRowVersion srcVersion;
47                 DbType dbType = DbType.AnsiString;
48                 int offset = 0;
49                 bool sizeSet = false;
50                 object value = DBNull.Value;
51                 OciLobLocator lobLocator = null;  // only if Blob or Clob
52                 IntPtr bindOutValue = IntPtr.Zero;
53                 OciDateTimeDescriptor dateTimeDesc = null;
54
55                 OracleParameterCollection container = null;
56                 OciBindHandle bindHandle;
57                 OciErrorHandle errorHandle;
58                 OracleConnection connection;
59                 byte[] bytes = null;
60                 IntPtr bindValue = IntPtr.Zero;
61
62                 short indicator = 0; // TODO: handle indicator to indicate NULL value for OUT parameters
63                 int bindSize = 0;
64
65                 #endregion // Fields
66
67                 #region Constructors
68
69                 // constructor for cloning the object
70                 internal OracleParameter (OracleParameter value) {
71                         this.name = value.name;
72                         this.oracleType = value.oracleType;
73                         this.ociType = value.ociType;
74                         this.size = value.size;
75                         this.direction = value.direction;
76                         this.isNullable = value.isNullable;
77                         this.precision = value.precision;
78                         this.scale = value.scale;
79                         this.srcColumn = value.srcColumn;
80                         this.srcVersion = value.srcVersion;
81                         this.dbType = value.dbType;
82                         this.offset = value.offset;
83                         this.sizeSet = value.sizeSet;
84                         this.value = value.value;
85                         this.lobLocator = value.lobLocator;
86                 }
87
88                 public OracleParameter ()
89                         : this (String.Empty, OracleType.VarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
90                 {
91                 }
92
93                 public OracleParameter (string name, object value)
94                 {
95                         this.name = name;
96                         this.value = value;
97                         SourceVersion = DataRowVersion.Current;
98                         InferOracleType (value);
99                 }
100
101                 public OracleParameter (string name, OracleType dataType)
102                         : this (name, dataType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
103                 {
104                 }
105
106                 public OracleParameter (string name, OracleType dataType, int size)
107                         : this (name, dataType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
108                 {
109                 }
110
111                 public OracleParameter (string name, OracleType dataType, int size, string srcColumn)
112                         : this (name, dataType, size, ParameterDirection.Input, false, 0, 0, srcColumn, DataRowVersion.Current, null)
113                 {
114                 }
115
116                 public OracleParameter (string name, OracleType dataType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string srcColumn, DataRowVersion srcVersion, object value)
117                 {
118                         this.name = name;
119                         this.size = size;
120                         this.value = value;
121
122                         OracleType = dataType;
123                         Direction = direction;
124                         SourceColumn = srcColumn;
125                         SourceVersion = srcVersion;
126                 }
127
128                 #endregion // Constructors
129
130                 #region Properties
131
132                 internal OracleParameterCollection Container {
133                         get { return container; }
134                         set { container = value; }
135                 }
136
137                 [Browsable (false)]
138                 [RefreshProperties (RefreshProperties.All)]
139                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
140                 public DbType DbType {
141                         get { return dbType; }
142                         set { SetDbType (value); }
143                 }
144
145                 [DefaultValue (ParameterDirection.Input)]
146                 [RefreshProperties (RefreshProperties.All)]
147                 public ParameterDirection Direction {
148                         get { return direction; }
149                         set { direction = value; }
150                 }
151
152                 [Browsable (false)]
153                 [DesignOnly (true)]
154                 [DefaultValue (false)]
155                 [EditorBrowsable (EditorBrowsableState.Never)]
156                 public bool IsNullable {
157                         get { return isNullable; }
158                         set { isNullable = value; }
159                 }
160
161                 [DefaultValue (0)]
162                 [Browsable (false)]
163                 public int Offset {
164                         get { return offset; }
165                         set { offset = value; }
166                 }
167
168                 [DefaultValue (OracleType.VarChar)]
169                 [RefreshProperties (RefreshProperties.All)]
170                 public OracleType OracleType {
171                         get { return oracleType; }
172                         set { SetOracleType (value); }
173                 }
174                 
175                 [DefaultValue ("")]
176                 public string ParameterName {
177                         get { return name; }
178                         set { name = value; }
179                 }
180
181                 [DefaultValue (0)]
182                 public byte Precision {
183                         get { return precision; }
184                         set { /* NO EFFECT*/ }
185                 }
186
187                 [DefaultValue (0)]
188                 public byte Scale {
189                         get { return scale; }
190                         set { /* NO EFFECT*/ }
191                 }
192
193                 [DefaultValue (0)]
194                 public int Size {
195                         get { return size; }
196                         set { 
197                                 sizeSet = true;
198                                 size = value; 
199                         }
200                 }
201
202                 [DefaultValue ("")]
203                 public string SourceColumn {
204                         get { return srcColumn; }
205                         set { srcColumn = value; }
206                 }
207
208                 [DefaultValue ("Current")]
209                 public DataRowVersion SourceVersion {
210                         get { return srcVersion; }
211                         set { srcVersion = value; }
212                 }
213
214                 [DefaultValue (null)]
215                 [RefreshProperties (RefreshProperties.All)]
216                 [TypeConverter (typeof(StringConverter))]
217                 public object Value {
218                         get { return this.value; }
219                         set { this.value = value; }
220                 }
221
222                 #endregion // Properties
223
224                 #region Methods
225
226                 private void AssertSizeIsSet ()
227                 {
228                         switch (ociType) {
229                         case OciDataType.VarChar2:
230                         case OciDataType.String:
231                         case OciDataType.VarChar:
232                         case OciDataType.Char:
233                         case OciDataType.CharZ:
234                         case OciDataType.OciString:
235                                 if (!sizeSet)
236                                         throw new Exception ("Size must be set.");
237                                 break;
238                         default:
239                                 break;
240                         }
241                 }
242
243                 internal void Bind (OciStatementHandle statement, OracleConnection connection) 
244                 {
245                         errorHandle = connection.ErrorHandle;
246
247                         if (bindHandle == null)
248                                 bindHandle = new OciBindHandle ((OciHandle) statement);
249
250                         IntPtr tmpHandle = bindHandle.Handle;
251
252                         if (Direction != ParameterDirection.Input)
253                                 AssertSizeIsSet ();
254                         if (!sizeSet)
255                                 size = InferSize ();
256
257                         bindSize = size;
258                         object v = value;
259                         int status = 0;
260                         OciDataType bindType = ociType;
261                         int rsize = 0;
262
263                         // TODO: handle InputOutput and Return parameters
264                         if (direction == ParameterDirection.Output) {
265                                 // TODO: need to figure out how OracleParameter
266                                 //       which uses OciBindHandle to share code
267                                 //       with OciDefineHandle
268                                 switch(ociType) {
269                                         case OciDataType.VarChar2:
270                                         case OciDataType.String:
271                                         case OciDataType.VarChar:
272                                         case OciDataType.Char:
273                                         case OciDataType.CharZ:
274                                         case OciDataType.OciString:
275                                                 bindType = OciDataType.Char;
276                                                 bindSize = size * 2;
277                                                 bindOutValue = Marshal.AllocHGlobal (bindSize);
278                                                 break;
279                                         case OciDataType.RowIdDescriptor:
280                                                 size = 10;
281                                                 bindType = OciDataType.Char;
282                                                 bindSize = size * 2;
283                                                 bindOutValue = Marshal.AllocHGlobal (bindSize);
284                                                 break;
285                                         case OciDataType.Date:
286                                                 bindSize = 7;
287                                                 bindType = OciDataType.Date;
288                                                 bindOutValue = Marshal.AllocHGlobal (bindSize);
289                                                 break;
290                                         case OciDataType.TimeStamp:
291                                                 dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
292                                                 if (dateTimeDesc == null) {
293                                                         OciErrorInfo info = connection.ErrorHandle.HandleError ();
294                                                         throw new OracleException (info.ErrorCode, info.ErrorMessage);
295                                                 }
296                                                 dateTimeDesc.ErrorHandle = connection.ErrorHandle;
297                                                 bindSize = 11;
298                                                 bindType = OciDataType.TimeStamp;
299                                                 bindOutValue = dateTimeDesc.Handle;
300                                                 break;
301                                         case OciDataType.Number:
302                                                 bindSize = 22;
303                                                 bindType = OciDataType.Char;
304                                                 bindOutValue = Marshal.AllocHGlobal (bindSize);
305                                                 break;
306                                         case OciDataType.Long:
307                                         case OciDataType.LongVarChar:
308                                                 // LAMESPEC: you don't know size until you get it;
309                                                 // therefore, you must allocate an insane size
310                                                 // see OciDefineHandle
311                                                 bindSize = OciDefineHandle.LongVarCharMaxValue;
312                                                 bindOutValue = Marshal.AllocHGlobal (bindSize);
313                                                 bindType = OciDataType.LongVarChar;
314                                                 break;
315                                         case OciDataType.Blob:
316                                         case OciDataType.Clob:
317                                                 bindSize = -1;
318                                                 lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
319                                                 if (lobLocator == null) {
320                                                         OciErrorInfo info = connection.ErrorHandle.HandleError ();
321                                                         throw new OracleException (info.ErrorCode, info.ErrorMessage);
322                                                 }
323                                                 bindOutValue = lobLocator.Handle;
324                                                 lobLocator.ErrorHandle = connection.ErrorHandle;
325                                                 lobLocator.Service = statement.Service;
326                                                 break;
327                                         default:
328                                                 // define other types
329                                                 throw new NotImplementedException ();
330                                 }
331                                 bindValue = bindOutValue;
332                         }
333                         else if (v == DBNull.Value || v == null) {
334                                 indicator = 0;
335                                 bindType = OciDataType.VarChar2;
336                                 bindSize = 0;
337                         }
338                         else {
339                                 // TODO: do other data types and oracle data types
340                                 // should I be using IConvertible to convert?
341                                 string sDate = "";
342                                 DateTime dt = DateTime.MinValue;
343                                 if (oracleType == OracleType.Timestamp){
344                                         bindType = OciDataType.TimeStamp;
345                                         bindSize = 11;
346                                         dt = DateTime.MinValue;
347                                         sDate = "";
348                                         if (v is String){
349                                                 sDate = (string) v;
350                                                 dt = DateTime.Parse (sDate);
351                                         }
352                                         else if (v is DateTime)
353                                                 dt = (DateTime) v;
354                                         else if (v is OracleString){
355                                                 sDate = (string) v;
356                                                 dt = DateTime.Parse (sDate);
357                                         }
358                                         else
359                                                 throw new NotImplementedException (); // ?
360                                         
361                                         short year = (short) dt.Year;
362                                         byte month = (byte) dt.Month;
363                                         byte day = (byte) dt.Day;
364                                         byte hour = (byte) dt.Hour;
365                                         byte min = (byte) dt.Minute;
366                                         byte sec = (byte) dt.Second;
367                                         uint fsec = (uint) dt.Millisecond;
368                                         string timezone = "";
369                                         dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
370                                         if (dateTimeDesc == null) {
371                                                 OciErrorInfo info = connection.ErrorHandle.HandleError ();
372                                                 throw new OracleException (info.ErrorCode, info.ErrorMessage);
373                                         }
374                                         dateTimeDesc.ErrorHandle = connection.ErrorHandle;
375                                         dateTimeDesc.SetDateTime (connection.Session,
376                                                 connection.ErrorHandle, 
377                                                 year, month, day, hour, min, sec, fsec,
378                                                 timezone);
379                                 }
380                                 else if (oracleType == OracleType.DateTime) {
381                                         sDate = "";
382                                         dt = DateTime.MinValue;
383                                         if (v is String) {
384                                                 sDate = (string) v;
385                                                 dt = DateTime.Parse (sDate);
386                                         }
387                                         else if (v is DateTime)
388                                                 dt = (DateTime) v;
389                                         else if (v is OracleString) {
390                                                 sDate = (string) v;
391                                                 dt = DateTime.Parse (sDate);
392                                         }
393                                         else if (v is OracleDateTime) {
394                                                 OracleDateTime odt = (OracleDateTime) v;
395                                                 dt = (DateTime) odt.Value;
396                                         }
397                                         else
398                                                 throw new NotImplementedException (); // ?
399
400                                         bytes = PackDate (dt);
401                                         bindType = OciDataType.Date;
402                                         bindSize = bytes.Length;
403                                 }
404                                 else if (oracleType == OracleType.Blob) {
405                                         bytes = (byte[]) v;
406                                         bindType = OciDataType.LongRaw;
407                                         bindSize = bytes.Length;
408                                 }
409                                 else if (oracleType == OracleType.Clob) {
410                                         string sv = (string) v;
411                                         rsize = 0;
412                         
413                                         // Get size of buffer
414                                         OciCalls.OCIUnicodeToCharSet (statement.Parent, null, sv, out rsize);
415                         
416                                         // Fill buffer
417                                         bytes = new byte[rsize];
418                                         OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, sv, out rsize);
419
420                                         bindType = OciDataType.Long;
421                                         bindSize = bytes.Length;
422                                 }
423                                 else if (oracleType == OracleType.Raw) {
424                                         byte[] val = v as byte[];
425                                         bindValue = Marshal.AllocHGlobal (val.Length);
426                                         Marshal.Copy (val, 0, bindValue, val.Length);
427                                         bindSize = val.Length;
428                                 }
429                                 else {
430                                         string svalue = v.ToString ();
431                                         rsize = 0;
432                         
433                                         // Get size of buffer
434                                         OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
435                         
436                                         // Fill buffer
437                                         bytes = new byte[rsize];
438                                         OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
439
440                                         bindType = OciDataType.VarChar2;
441                                         bindSize = v.ToString ().Length;
442                                 }
443                         }
444
445                         if (dateTimeDesc != null) {
446                                 bindValue = dateTimeDesc.Handle;
447                                 status = OciCalls.OCIBindByNameRef (statement,
448                                         out tmpHandle,
449                                         connection.ErrorHandle,
450                                         ParameterName,
451                                         ParameterName.Length,
452                                         ref bindValue,
453                                         bindSize,
454                                         bindType,
455                                         ref indicator,
456                                         IntPtr.Zero,
457                                         IntPtr.Zero,
458                                         0,
459                                         IntPtr.Zero,
460                                         0);
461                         }
462                         else if (bytes != null) {
463                                 status = OciCalls.OCIBindByNameBytes (statement,
464                                         out tmpHandle,
465                                         connection.ErrorHandle,
466                                         ParameterName,
467                                         ParameterName.Length,
468                                         bytes,
469                                         bindSize,
470                                         bindType,
471                                         ref indicator,
472                                         IntPtr.Zero,
473                                         IntPtr.Zero,
474                                         0,
475                                         IntPtr.Zero,
476                                         0);
477                         }
478                         else {
479                                 status = OciCalls.OCIBindByName (statement,
480                                         out tmpHandle,
481                                         connection.ErrorHandle,
482                                         ParameterName,
483                                         ParameterName.Length,
484                                         bindValue,
485                                         bindSize,
486                                         bindType,
487                                         ref indicator,
488                                         IntPtr.Zero,
489                                         IntPtr.Zero,
490                                         0,
491                                         IntPtr.Zero,
492                                         0);
493                         }
494
495                         if (status != 0) {
496                                 OciErrorInfo info = connection.ErrorHandle.HandleError ();
497                                 throw new OracleException (info.ErrorCode, info.ErrorMessage);
498                         }
499
500                         bindHandle.SetHandle (tmpHandle);
501                 }
502
503                 object ICloneable.Clone ()
504                 {
505                         return new OracleParameter(this);
506                 }
507
508                 private void InferOracleType (object value)
509                 {
510                         Type type = value.GetType ();
511                         string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
512                         switch (type.FullName) {
513                         case "System.Int64":
514                                 SetOracleType (OracleType.Number);
515                                 break;
516                         case "System.Boolean":
517                         case "System.Byte":
518                                 SetOracleType (OracleType.Byte);
519                                 break;
520                         case "System.String":
521                                 SetOracleType (OracleType.VarChar);
522                                 break;
523                         case "System.DateTime":
524                                 SetOracleType (OracleType.DateTime);
525                                 break;
526                         case "System.Decimal":
527                                 SetOracleType (OracleType.Number);
528                                 //scale = ((decimal) value).Scale;
529                                 break;
530                         case "System.Double":
531                                 SetOracleType (OracleType.Double);
532                                 break;
533                         case "System.Byte[]":
534                         case "System.Guid":
535                                 SetOracleType (OracleType.Raw);
536                                 break;
537                         case "System.Int32":
538                                 SetOracleType (OracleType.Int32);
539                                 break;
540                         case "System.Single":
541                                 SetOracleType (OracleType.Float);
542                                 break;
543                         case "System.Int16":
544                                 SetOracleType (OracleType.Int16);
545                                 break;
546                         default:
547                                 throw new ArgumentException (exception);
548                         }
549                 }
550
551                 private int InferSize ()
552                 {
553                         int newSize = 0;
554                         
555                         switch (ociType) {
556                         case OciDataType.VarChar2:
557                         case OciDataType.String:
558                         case OciDataType.VarChar:
559                         case OciDataType.Char:
560                         case OciDataType.CharZ:
561                         case OciDataType.OciString:
562                         case OciDataType.Long:
563                         case OciDataType.LongVarChar:
564                                 if (value == null || value == DBNull.Value)
565                                         newSize = 0;
566                                 else
567                                         newSize = value.ToString ().Length;
568                                 break;
569                         case OciDataType.RowIdDescriptor:
570                                 newSize = 10;
571                                 break;
572                         case OciDataType.Integer:
573                         case OciDataType.Number:
574                         case OciDataType.Float:
575                                 newSize = 22;
576                                 break;
577                         case OciDataType.Date:
578                                 newSize = 7;
579                                 break;
580                         case OciDataType.TimeStamp:
581                                 newSize = 11;
582                                 break;          
583                         case OciDataType.Blob:
584                         case OciDataType.Clob:
585                                 newSize = -1;
586                                 break;                                  
587                         default:
588                                 if (value == null || value == DBNull.Value)
589                                         newSize = 0;
590                                 else
591                                         newSize = value.ToString ().Length;
592                                 break;
593                         }
594
595                         sizeSet = true;
596
597                         return newSize;
598                 }
599
600                 private void SetDbType (DbType type)
601                 {
602                         string exception = String.Format ("No mapping exists from DbType {0} to a known OracleType.", type);
603                         switch (type) {
604                         case DbType.AnsiString:
605                                 oracleType = OracleType.VarChar;
606                                 ociType = OciDataType.VarChar;
607                                 break;
608                         case DbType.AnsiStringFixedLength:
609                                 oracleType = OracleType.Char;
610                                 ociType = OciDataType.Char;
611                                 break;
612                         case DbType.Binary:
613                         case DbType.Guid:
614                                 oracleType = OracleType.Raw;
615                                 ociType = OciDataType.Raw;
616                                 break;
617                         case DbType.Boolean:
618                         case DbType.Byte:
619                                 oracleType = OracleType.Byte;
620                                 ociType = OciDataType.Integer;
621                                 break;
622                         case DbType.Currency:
623                         case DbType.Decimal:
624                         case DbType.Int64:
625                                 oracleType = OracleType.Number;
626                                 ociType = OciDataType.Number;
627                                 break;
628                         case DbType.Date:
629                         case DbType.DateTime:
630                         case DbType.Time:
631                                 oracleType = OracleType.DateTime;
632                                 ociType = OciDataType.Char;
633                                 break;
634                         case DbType.Double:
635                                 oracleType = OracleType.Double;
636                                 ociType = OciDataType.Float;
637                                 break;
638                         case DbType.Int16:
639                                 oracleType = OracleType.Int16;
640                                 ociType = OciDataType.Integer;
641                                 break;
642                         case DbType.Int32:
643                                 oracleType = OracleType.Int32;
644                                 ociType = OciDataType.Integer;
645                                 break;
646                         case DbType.Object:
647                                 oracleType = OracleType.Blob;
648                                 ociType = OciDataType.Blob;
649                                 break;
650                         case DbType.Single:
651                                 oracleType = OracleType.Float;
652                                 ociType = OciDataType.Float;
653                                 break;
654                         case DbType.String:
655                                 oracleType = OracleType.NVarChar;
656                                 ociType = OciDataType.VarChar;
657                                 break;
658                         case DbType.StringFixedLength:
659                                 oracleType = OracleType.NChar;
660                                 ociType = OciDataType.Char;
661                                 break;
662                         default:
663                                 throw new ArgumentException (exception);
664                         }
665                         dbType = type;
666
667                 }
668
669                 private void SetOracleType (OracleType type)
670                 {
671                         string exception = String.Format ("No mapping exists from OracleType {0} to a known DbType.", type);
672                         switch (type) {
673                         case OracleType.BFile:
674                         case OracleType.Blob:
675                                 dbType = DbType.Binary;
676                                 ociType = OciDataType.Blob;
677                                 break;
678                         case OracleType.LongRaw:
679                         case OracleType.Raw:
680                                 dbType = DbType.Binary;
681                                 ociType = OciDataType.Raw;
682                                 break;
683                         case OracleType.Byte:
684                                 dbType = DbType.Byte;
685                                 ociType = OciDataType.Number;
686                                 break;
687                         case OracleType.Char:
688                                 dbType = DbType.AnsiString;
689                                 ociType = OciDataType.Char;
690                                 break;
691                         case OracleType.Clob:
692                                 dbType = DbType.AnsiString;
693                                 ociType = OciDataType.Clob;
694                                 break;
695                         case OracleType.LongVarChar:
696                         case OracleType.RowId:
697                         case OracleType.VarChar:
698                                 dbType = DbType.AnsiString;
699                                 ociType = OciDataType.VarChar;
700                                 break;
701                         case OracleType.Cursor:
702                         case OracleType.IntervalDayToSecond:
703                                 dbType = DbType.AnsiStringFixedLength;
704                                 ociType = OciDataType.Char;
705                                 break;
706                         case OracleType.Timestamp:
707                         case OracleType.TimestampLocal:
708                         case OracleType.TimestampWithTZ:
709                                 dbType = DbType.DateTime;
710                                 ociType = OciDataType.TimeStamp;
711                                 break;
712                         case OracleType.DateTime:
713                                 dbType = DbType.DateTime;
714                                 ociType = OciDataType.Date;
715                                 break;
716                         case OracleType.Double:
717                                 dbType = DbType.Double;
718                                 ociType = OciDataType.Number;
719                                 break;
720                         case OracleType.Float:
721                                 dbType = DbType.Single;
722                                 ociType = OciDataType.Number;
723                                 break;
724                         case OracleType.Int16:
725                                 dbType = DbType.Int16;
726                                 ociType = OciDataType.Number;
727                                 break;
728                         case OracleType.Int32:
729                         case OracleType.IntervalYearToMonth:
730                                 dbType = DbType.Int32;
731                                 ociType = OciDataType.Number;
732                                 break;
733                         case OracleType.NChar:
734                                 dbType = DbType.StringFixedLength;
735                                 ociType = OciDataType.Char;
736                                 break;
737                         case OracleType.NClob:
738                         case OracleType.NVarChar:
739                                 dbType = DbType.String;
740                                 ociType = OciDataType.Char;
741                                 break;
742                         case OracleType.Number:
743                                 dbType = DbType.VarNumeric;
744                                 ociType = OciDataType.Number;
745                                 break;
746                         case OracleType.SByte:
747                                 dbType = DbType.SByte;
748                                 ociType = OciDataType.Number;
749                                 break;
750                         case OracleType.UInt16:
751                                 dbType = DbType.UInt16;
752                                 ociType = OciDataType.Number;
753                                 break;
754                         case OracleType.UInt32:
755                                 dbType = DbType.UInt32;
756                                 ociType = OciDataType.Number;
757                                 break;
758                         default:
759                                 throw new ArgumentException (exception);
760                         }
761
762                         oracleType = type;
763                 }
764
765                 public override string ToString ()
766                 {
767                         return ParameterName;
768                 }
769
770                 internal void Update (OracleCommand cmd) 
771                 {
772                         // used to update the parameter value
773                         // for Output, the output of InputOutput, and Return parameters
774                         value = DBNull.Value;
775                         if (indicator == -1)
776                                 return;
777
778                         byte[] buffer = null;
779                         object tmp = null;
780
781                         switch (ociType) {
782                         case OciDataType.VarChar2:
783                         case OciDataType.String:
784                         case OciDataType.VarChar:
785                         case OciDataType.Char:
786                         case OciDataType.CharZ:
787                         case OciDataType.OciString:
788                         case OciDataType.RowIdDescriptor:
789                                 buffer = new byte [Size];
790                                 Marshal.Copy (bindOutValue, buffer, 0, Size);
791                                 
792                                 // Get length of returned string
793                                 int     rsize = 0;
794                                 IntPtr  env = cmd.Connection.Environment;
795                                 OciCalls.OCICharSetToUnicode (env, null, buffer, out rsize);
796                         
797                                 // Get string
798                                 StringBuilder ret = new StringBuilder(rsize);
799                                 OciCalls.OCICharSetToUnicode (env, ret, buffer, out rsize);
800         
801                                 value = ret.ToString ();
802                                 break;
803                         case OciDataType.Integer:
804                         case OciDataType.Number:
805                         case OciDataType.Float:
806                                 tmp = Marshal.PtrToStringAnsi (bindOutValue, bindSize);
807                                 if (tmp != null)
808                                         value = Decimal.Parse (String.Copy ((string) tmp));
809                                 break;
810                         case OciDataType.TimeStamp:
811                                 value = dateTimeDesc.GetDateTime (connection.Environment, dateTimeDesc.ErrorHandle);
812                                 break;
813                         case OciDataType.Date:
814                                 value = UnpackDate (bindOutValue);
815                                 break;  
816                         case OciDataType.Blob:
817                         case OciDataType.Clob:
818                                 OracleLob lob = new OracleLob (lobLocator, ociType);
819                                 lob.connection = connection;
820                                 value = lob;
821                                 break;
822                         default:
823                                 throw new NotImplementedException ();
824                         }
825                 }
826
827                 // copied from OciDefineHandle
828                 [MonoTODO ("Be able to handle negative dates... i.e. BCE.")]
829                 internal DateTime UnpackDate (IntPtr dateValue)
830                 {
831                         byte century = Marshal.ReadByte (dateValue, 0);
832                         byte year = Marshal.ReadByte (dateValue, 1);
833                         byte month = Marshal.ReadByte (dateValue, 2);
834                         byte day = Marshal.ReadByte (dateValue, 3);
835                         byte hour = Marshal.ReadByte (dateValue, 4);
836                         byte minute = Marshal.ReadByte (dateValue, 5);
837                         byte second = Marshal.ReadByte (dateValue, 6);
838
839                         return new DateTime ((century - 100) * 100 + (year - 100),
840                                                 month,
841                                                 day,
842                                                 hour - 1,
843                                                 minute - 1,
844                                                 second - 1);
845
846                 }
847
848                 internal byte[] PackDate (DateTime dateValue) 
849                 {
850                         byte[] buffer = new byte[7];
851
852                         buffer[0] = (byte)((dateValue.Year / 100) + 100); //century
853                         buffer[1] = (byte)((dateValue.Year % 100) + 100); // Year
854                         buffer[2] = (byte)dateValue.Month;
855                         buffer[3] = (byte)dateValue.Day;
856                         buffer[4] = (byte)(dateValue.Hour+1);
857                         buffer[5] = (byte)(dateValue.Minute+1);
858                         buffer[6] = (byte)(dateValue.Second+1);
859
860                         return buffer;
861                 }
862
863                 #endregion // Methods
864
865                 internal sealed class OracleParameterConverter : ExpandableObjectConverter
866                 {
867                         public OracleParameterConverter ()
868                         {
869                         }
870
871                         [MonoTODO]
872                         public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
873                         {
874                                 throw new NotImplementedException ();
875                         }
876
877                         [MonoTODO]
878                         public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
879                         {
880                                 throw new NotImplementedException ();
881                         }
882                 }
883         }
884 }