Merge pull request #1304 from slluis/mac-proxy-autoconfig
[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 <monodanmorg@yahoo.com>
13 //    Hubert FONGARNAND <informatique.internet@fiducial.fr>
14 //        Veerapuram Varadhan  <vvaradhan@novell.com>   
15 //
16 // Copyright (C) Tim Coleman , 2003
17 // Copyright (C) Daniel Morgan, 2005, 2008, 2009
18 // Copyright (C) Hubert FONGARNAND, 2005
19 // Copyright (C) Novell Inc, 2009
20 //
21 // Licensed under the MIT/X11 License.
22 //
23
24 using System;
25 using System.Collections;
26 using System.ComponentModel;
27 using System.Data;
28 #if NET_2_0
29 using System.Data.Common;
30 #endif
31 using System.Data.SqlTypes;
32 using System.Data.OracleClient.Oci;
33 using System.Globalization;
34 using System.Runtime.InteropServices;
35 using System.Text;
36
37 namespace System.Data.OracleClient
38 {
39         [TypeConverter (typeof(OracleParameter.OracleParameterConverter))]
40         public sealed class OracleParameter : 
41 #if NET_2_0
42                 DbParameter, IDbDataParameter, ICloneable,
43 #else
44                 MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable,
45 #endif
46                 IDisposable
47         {
48                 #region Fields
49
50                 string name;
51                 OracleType oracleType = OracleType.VarChar;
52                 OciDataType ociType;
53                 int size;
54                 ParameterDirection direction = ParameterDirection.Input;
55                 bool isNullable;
56                 byte precision;
57                 byte scale;
58                 string srcColumn;
59 #if NET_2_0
60                 bool sourceColumnNullMapping;
61 #endif
62                 DataRowVersion srcVersion;
63                 DbType dbType = DbType.AnsiString;
64                 int offset;
65                 bool sizeSet;
66                 bool oracleTypeSet;
67                 object value = DBNull.Value;
68                 OciLobLocator lobLocator;  // only if Blob or Clob
69                 IntPtr bindOutValue = IntPtr.Zero;
70                 IntPtr indicator = IntPtr.Zero;
71                 OciDateTimeDescriptor dateTimeDesc;
72                 IntPtr cursor = IntPtr.Zero;
73
74                 OracleParameterCollection container;
75                 OciBindHandle bindHandle;
76                 OracleConnection connection;
77                 byte[] bytes;
78                 IntPtr bindValue = IntPtr.Zero;
79                 bool useRef;
80                 OciDataType bindType;
81
82                 int bindSize;
83                 bool sizeManuallySet;
84
85                 #endregion // Fields
86
87                 #region Constructors
88
89                 // constructor for cloning the object
90                 private OracleParameter (OracleParameter value)
91                 {
92                         this.name = value.name;
93                         this.oracleType = value.oracleType;
94                         this.ociType = value.ociType;
95                         this.size = value.size;
96                         this.direction = value.direction;
97                         this.isNullable = value.isNullable;
98                         this.precision = value.precision;
99                         this.scale = value.scale;
100                         this.srcColumn = value.srcColumn;
101                         this.srcVersion = value.srcVersion;
102                         this.dbType = value.dbType;
103                         this.offset = value.offset;
104                         this.sizeSet = value.sizeSet;
105                         this.value = value.value;
106                         this.lobLocator = value.lobLocator;
107                         this.oracleTypeSet = value.oracleTypeSet;
108                         this.indicator = OciCalls.AllocateClear (sizeof(short));
109                 }
110
111                 public OracleParameter ()
112                 {
113                         this.name = String.Empty;
114                         this.oracleType = OracleType.VarChar;
115                         this.size = 0;
116                         this.direction = ParameterDirection.Input;
117                         this.isNullable = false;
118                         this.precision = 0;
119                         this.scale = 0;
120                         this.srcColumn = String.Empty;
121                         this.srcVersion = DataRowVersion.Current;
122                         this.value = null;
123                         this.oracleTypeSet = false;
124                         this.indicator = OciCalls.AllocateClear (sizeof(short));
125                 }
126
127                 public OracleParameter (string name, object value)
128                 {
129                         this.name = name;
130                         this.value = value;
131
132                         srcColumn = string.Empty;
133                         SourceVersion = DataRowVersion.Current;
134                         InferOracleType (value);                        
135                         this.indicator = OciCalls.AllocateClear (sizeof(short));
136 #if NET_2_0
137                         // Find the OciType before inferring for the size
138                         if (value != null && value != DBNull.Value) {
139                                 this.sizeSet = true;
140                                 this.size = InferSize ();
141                         }
142 #endif
143                 }
144
145                 public OracleParameter (string name, OracleType oracleType)
146                         : this (name, oracleType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
147                 {
148                 }
149
150                 public OracleParameter (string name, OracleType oracleType, int size)
151                         : this (name, oracleType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
152                 {
153                 }
154
155                 public OracleParameter (string name, OracleType oracleType, int size, string srcColumn)
156                         : this (name, oracleType, size, ParameterDirection.Input, false, 0, 0, srcColumn, DataRowVersion.Current, null)
157                 {
158                 }
159
160 #if NET_2_0
161                 public OracleParameter (string name, OracleType oracleType, int size, ParameterDirection direction, string sourceColumn, DataRowVersion sourceVersion, bool sourceColumnNullMapping, object value)
162                 {
163                         this.name = name;
164                         if (size < 0)
165                                 throw new ArgumentException("Size must be not be negative.");
166                         
167                         this.value = value;
168                         this.size = size;
169                         Direction = direction;
170
171                         // set sizeSet to true iff value is not-null or non-zero size value
172                         if (((value != null && value != DBNull.Value) || Direction == ParameterDirection.Output) && 
173                             size > 0)                       
174                                 this.sizeSet = true;
175
176                         SourceColumnNullMapping = sourceColumnNullMapping;
177                         OracleType = oracleType;
178                         SourceColumn = sourceColumn;
179                         SourceVersion = sourceVersion;
180                         this.indicator = OciCalls.AllocateClear (sizeof(short));
181                 }
182 #endif
183
184                 public OracleParameter (string name, OracleType oracleType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string srcColumn, DataRowVersion srcVersion, object value)
185                 {
186                         this.name = name;
187                         if (size < 0)
188                                 throw new ArgumentException("Size must be not be negative.");
189                         
190                         this.value = value;
191                         this.size = size;
192
193                         Direction = direction;
194                         
195                         // set sizeSet to true iff value is not-null or non-zero size value
196                         if (((value != null && value != DBNull.Value) || Direction == ParameterDirection.Output) && 
197                             size > 0)                       
198                                 this.sizeSet = true;
199
200                         this.isNullable = isNullable;
201                         this.precision = precision;
202                         this.scale = scale;
203
204                         OracleType = oracleType;
205                         SourceColumn = srcColumn;
206                         SourceVersion = srcVersion;
207                         this.indicator = OciCalls.AllocateClear (sizeof(short));
208                 }
209         
210                 ~OracleParameter ()
211                 {
212                         Dispose(false);
213                 }
214
215                 #endregion // Constructors
216
217                 #region Properties
218
219                 internal OracleParameterCollection Container {
220                         get { return container; }
221                         set { container = value; }
222                 }
223
224                 internal short Indicator {
225                         get { return (Marshal.ReadInt16(indicator)); }
226                         set { Marshal.WriteInt16(indicator, value); }
227                 }
228
229 #if !NET_2_0
230                 [Browsable (false)]
231                 [RefreshProperties (RefreshProperties.All)]
232                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
233 #endif
234                 public
235 #if NET_2_0
236                 override
237 #endif
238                 DbType DbType {
239                         get { return dbType; }
240                         set { SetDbType (value); }
241                 }
242
243 #if !NET_2_0
244                 [DefaultValue (ParameterDirection.Input)]
245 #endif
246                 [RefreshProperties (RefreshProperties.All)]
247                 public
248 #if NET_2_0
249                 override
250 #endif
251                 ParameterDirection Direction {
252                         get { return direction; }
253                         set { 
254                                 direction = value; 
255                                 if (this.size > 0 && direction == ParameterDirection.Output)
256                                         this.sizeSet = true;
257                         }
258                 }
259
260 #if !NET_2_0
261                 [Browsable (false)]
262                 [DesignOnly (true)]
263                 [DefaultValue (false)]
264                 [EditorBrowsable (EditorBrowsableState.Never)]
265 #endif
266                 public
267 #if NET_2_0
268                 override
269 #endif
270                 bool IsNullable {
271                         get { return isNullable; }
272                         set { isNullable = value; }
273                 }
274
275 #if NET_2_0
276                 [EditorBrowsable (EditorBrowsableState.Advanced)]
277 #else
278                 [DefaultValue (0)]
279 #endif
280                 [Browsable (false)]
281                 public int Offset {
282                         get { return offset; }
283                         set { offset = value; }
284                 }
285
286                 [DefaultValue (OracleType.VarChar)]
287                 [RefreshProperties (RefreshProperties.All)]
288 #if NET_2_0
289                 [DbProviderSpecificTypeProperty (true)]
290 #endif
291                 public OracleType OracleType {
292                         get { return oracleType; }
293                         set { 
294                                 oracleTypeSet = true;
295                                 SetOracleType (value, false); 
296                         }
297                 }
298
299 #if !NET_2_0
300                 [DefaultValue ("")]
301 #endif
302                 public
303 #if NET_2_0
304                 override
305 #endif
306                 string ParameterName {
307                         get {
308                                 if (name == null)
309                                         return string.Empty;
310                                 return name;
311                         }
312                         set { name = value; }
313                 }
314
315 #if NET_2_0
316                 [Browsable (false)]
317                 [EditorBrowsable (EditorBrowsableState.Never)]
318                 [Obsolete("Set the precision of a decimal use the Math classes.")]
319 #else
320                 [DefaultValue (0)]
321 #endif
322                 public byte Precision {
323                         get { return precision; }
324                         set { /* NO EFFECT*/ }
325                 }
326
327 #if NET_2_0
328                 [Browsable (false)]
329                 [EditorBrowsable (EditorBrowsableState.Never)]
330                 [Obsolete("Set the precision of a decimal use the Math classes.")]
331 #else
332                 [DefaultValue (0)]
333 #endif
334                 public byte Scale {
335                         get { return scale; }
336                         set { /* NO EFFECT*/ }
337                 }
338
339 #if !NET_2_0
340                 [DefaultValue (0)]
341 #endif
342                 public
343 #if NET_2_0
344                 override
345 #endif
346                 int Size {
347                         get { return size; }
348                         set {
349                                 sizeSet = true;
350                                 size = value;
351                                 sizeManuallySet = true;
352                         }
353                 }
354
355 #if !NET_2_0
356                 [DefaultValue ("")]
357 #endif
358                 public
359 #if NET_2_0
360                 override
361 #endif
362                 string SourceColumn {
363                         get { return srcColumn; }
364                         set { srcColumn = value; }
365                 }
366
367 #if NET_2_0
368                 [MonoTODO]
369                 public override bool SourceColumnNullMapping {
370                         get { return sourceColumnNullMapping; }
371                         set { sourceColumnNullMapping = value; }
372                 }
373 #endif
374
375 #if !NET_2_0
376                 [DefaultValue ("Current")]
377 #endif
378                 public
379 #if NET_2_0
380                 override
381 #endif
382                 DataRowVersion SourceVersion {
383                         get { return srcVersion; }
384                         set { srcVersion = value; }
385                 }
386
387 #if !NET_2_0
388                 [DefaultValue (null)]
389 #endif
390                 [RefreshProperties (RefreshProperties.All)]
391                 [TypeConverter (typeof(StringConverter))]
392                 public
393 #if NET_2_0
394                 override
395 #endif
396                 object Value {
397                         get { return this.value; }
398                         set {
399                                 this.value = value;
400                                 if (!oracleTypeSet)
401                                         InferOracleType (value);
402 #if NET_2_0
403                                 if (value != null && value != DBNull.Value) {
404                                         this.size = InferSize ();
405                                         this.sizeSet = true;
406                                 }
407 #endif
408                         }
409                 }
410
411                 #endregion // Properties
412
413                 #region Methods
414
415                 private void AssertSizeIsSet ()
416                 {
417                         switch (ociType) {
418                         case OciDataType.VarChar2:
419                         case OciDataType.String:
420                         case OciDataType.VarChar:
421                         case OciDataType.Char:
422                         case OciDataType.CharZ:
423                         case OciDataType.OciString:
424                                 if (!sizeSet)
425                                         throw new Exception ("Size must be set.");
426                                 break;
427                         default:
428                                 break;
429                         }
430                 }
431
432                 internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos)
433                 {
434                         connection = con;
435
436                         if (bindHandle == null)
437                                 bindHandle = new OciBindHandle ((OciHandle) statement);
438
439                         IntPtr tmpHandle = bindHandle.Handle;
440
441                         if (Direction != ParameterDirection.Input)
442                                 AssertSizeIsSet ();
443                         if (!sizeSet)
444                                 size = InferSize ();
445
446                         bindSize = size;
447                         object v = value;
448                         int status = 0;
449                         bindType = ociType;
450                         int rsize = 0;
451
452                         string svalue;
453                         string sDate;
454                         DateTime dt;
455                         bool isnull = false;
456                         int byteCount;
457                         byte[] byteArrayLen;
458
459                         if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) {
460                                 if (v == null)
461                                         isnull = true;
462                                 else if (v is DBNull)
463                                         isnull = true;
464                                 else {
465                                         INullable mynullable = v as INullable;
466                                         if (mynullable != null)
467                                                 isnull = mynullable.IsNull;
468                                 }                                       
469                         } 
470
471                         if (isnull == true && direction == ParameterDirection.Input) {
472                                 bindType = OciDataType.VarChar2;
473                                 bindSize = 0;
474                         } else {
475                                 switch(ociType) {
476                                 case OciDataType.VarChar2:
477                                 case OciDataType.String:
478                                 case OciDataType.VarChar:
479                                 case OciDataType.Char:
480                                 case OciDataType.CharZ:
481                                 case OciDataType.OciString:
482                                         bindType = OciDataType.String;
483                                         svalue = "\0";
484                                         // convert value from managed type to type to marshal
485                                         if (direction == ParameterDirection.Input || 
486                                                 direction == ParameterDirection.InputOutput) {
487
488                                                 svalue = v.ToString ();
489
490                                                 if (direction == ParameterDirection.Input && size > 0 && svalue.Length > size)
491                                                         svalue = svalue.Substring(0, size);
492
493                                                 svalue = svalue.ToString () + '\0';
494                                                 
495                                                 // convert managed type to memory allocated earlier
496                                                 // in this case using OCIUnicodeToCharSet
497                                                 rsize = 0;
498                                                 // Get size of buffer
499                                                 status = OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
500
501                                                 if (direction == ParameterDirection.Input)
502                                                         bindSize = rsize;
503                                                 else {
504                                                         // this cannot be rsize because you need room for the output after the execute
505                                                         bindSize = Encoding.UTF8.GetMaxByteCount (Size + 1);
506                                                 }
507
508                                                 // allocate memory based on bind size
509                                                 bytes = new byte [bindSize];
510
511                                                 // Fill buffer
512                                                 status = OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
513                                         } else {
514                                                 // for Output and ReturnValue parameters, get size in bytes                                     
515                                                 bindSize = Encoding.UTF8.GetMaxByteCount (size + 1);
516                                                 // allocate memory for oracle to place the results for the Return or Output param                                               
517                                                 bytes = new byte [bindSize];
518                                         }
519                                         break;
520                                 case OciDataType.Date:
521                                         bindType = OciDataType.Date;
522                                         bindSize = 7;
523                                         // convert value from managed type to type to marshal
524                                         if (direction == ParameterDirection.Input || 
525                                                 direction == ParameterDirection.InputOutput) {
526
527                                                 if (isnull)
528                                                         bytes = new byte [7];
529                                                 else {
530                                                         sDate = "";
531                                                         dt = DateTime.MinValue;
532                                                         if (v is String) {
533                                                                 sDate = (string) v;
534                                                                 dt = DateTime.Parse (sDate);
535                                                         }
536                                                         else if (v is DateTime)
537                                                                 dt = (DateTime) v;
538                                                         else if (v is OracleString) {
539                                                                 sDate = v.ToString ();
540                                                                 dt = DateTime.Parse (sDate);
541                                                         }
542                                                         else if (v is OracleDateTime) {
543                                                                 OracleDateTime odt = (OracleDateTime) v;
544                                                                 dt = (DateTime) odt.Value;
545                                                         }
546                                                         else
547                                                                 throw new NotImplementedException ("For OracleType.DateTime, data type not implemented: " + v.GetType().ToString() + ".");
548
549                                                         // for Input and InputOuput, create byte array and pack DateTime into it
550                                                         bytes = PackDate (dt);
551                                                 }
552                                         } else  {
553                                                 // allocate 7-byte array for Output and ReturnValue to put date
554                                                 bytes = new byte [7];
555                                         }
556                                         break;
557                                 case OciDataType.TimeStamp:
558                                         dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
559                                         if (dateTimeDesc == null) {
560                                                 OciErrorInfo info = connection.ErrorHandle.HandleError ();
561                                                 throw new OracleException (info.ErrorCode, info.ErrorMessage);
562                                         }
563                                         dateTimeDesc.ErrorHandle = connection.ErrorHandle;
564                                         bindSize = 11;
565                                         bindType = OciDataType.TimeStamp;
566                                         bindOutValue = dateTimeDesc.Handle;
567                                         bindValue = dateTimeDesc.Handle;
568                                         useRef = true;
569                                         if (direction == ParameterDirection.Input || 
570                                                 direction == ParameterDirection.InputOutput) {
571
572                                                 dt = DateTime.MinValue;
573                                                 sDate = "";
574                                                 if (isnull)
575                                                         Indicator = -1;
576                                                 else if (v is String) {
577                                                         sDate = (string) v;
578                                                         dt = DateTime.Parse (sDate);
579                                                 }
580                                                 else if (v is DateTime)
581                                                         dt = (DateTime) v;
582                                                 else if (v is OracleString) {
583                                                         sDate = (string) v;
584                                                         dt = DateTime.Parse (sDate);
585                                                 }
586                                                 else if (v is OracleDateTime) {
587                                                         OracleDateTime odt = (OracleDateTime) v;
588                                                         dt = (DateTime) odt.Value;
589                                                 }
590                                                 else
591                                                         throw new NotImplementedException ("For OracleType.Timestamp, data type not implemented: " + v.GetType().ToString()); // ?
592
593                                                 short year = (short) dt.Year;
594                                                 byte month = (byte) dt.Month;
595                                                 byte day = (byte) dt.Day;
596                                                 byte hour = (byte) dt.Hour;
597                                                 byte min = (byte) dt.Minute;
598                                                 byte sec = (byte) dt.Second;
599                                                 uint fsec = (uint) dt.Millisecond;
600                                                 string timezone = "";
601                                                 dateTimeDesc.SetDateTime (connection.Session,
602                                                         connection.ErrorHandle,
603                                                         year, month, day, hour, min, sec, fsec,
604                                                         timezone);
605                                         }
606                                         break;
607                                 case OciDataType.Integer:
608                                 case OciDataType.Float:
609                                 case OciDataType.Number:
610                                         bindType = OciDataType.String;
611                                         Indicator = 0;
612                                         svalue = "\0";
613                                         // convert value from managed type to type to marshal
614                                         if (direction == ParameterDirection.Input || 
615                                                 direction == ParameterDirection.InputOutput) {
616
617                                                 svalue = null;
618                                                 if(v is IFormattable)
619                                                         svalue = ((IFormattable)v).ToString (null, con.SessionFormatProvider);
620                                                 else if (v is OracleNumber)
621                                                         svalue = ((OracleNumber)v).ToString(con.SessionFormatProvider);
622                                                 else
623                                                         svalue = v.ToString();
624
625                                                 svalue = svalue + "\0";
626
627                                                 rsize = 0;
628                                                 // Get size of buffer
629                                                 OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
630
631                                                 // Fill buffer 
632                                                 
633                                                 if (direction == ParameterDirection.Input)
634                                                         bindSize = rsize;
635                                                 else
636                                                         bindSize = 30; // need room for output possibly being bigger than the input
637                                                 
638                                                 bytes = new byte [bindSize];
639                                                 OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
640                                         } else {
641                                                 // Output and ReturnValue parameters allocate memory
642                                                 bindSize = 30;
643                                                 bytes = new byte [bindSize];
644                                         } 
645                                         break;
646                                 case OciDataType.Long:
647                                 case OciDataType.LongVarChar:
648                                         bindType = OciDataType.LongVarChar;
649
650                                         // FIXME: use piecewise fetching for Long, Clob, Blob, and Long Raw
651                                         // See http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci05bnd.htm#sthref724
652                                         
653                                         bindSize = Size + 5; // 4 bytes prepended for length, bytes, 1 byte NUL character
654
655                                         Indicator = 0;
656                                         svalue = "\0";
657                                         // convert value from managed type to type to marshal
658                                         if (direction == ParameterDirection.Input || 
659                                                 direction == ParameterDirection.InputOutput) {
660
661                                                 svalue = v.ToString () + '\0';
662                                         }
663
664                                         bytes = new byte [bindSize];
665                                         // LONG is only ANSI 
666                                         ASCIIEncoding enc = new ASCIIEncoding ();
667                                         
668                                         if (direction == ParameterDirection.Input || 
669                                                 direction == ParameterDirection.InputOutput) {
670                                                 if (svalue.Length > 0) {        
671                                                         byteCount = enc.GetBytes (svalue, 4, svalue.Length, bytes, 0);
672                                                         // LONG VARCHAR prepends a 4-byte length
673                                                         if (byteCount > 0) {
674                                                                 byteArrayLen = BitConverter.GetBytes ((uint) byteCount);
675                                                                 bytes[0] = byteArrayLen[0];
676                                                                 bytes[1] = byteArrayLen[1];
677                                                                 bytes[2] = byteArrayLen[2];
678                                                                 bytes[3] = byteArrayLen[3];
679                                                         }
680                                                 }
681                                         }
682                                         break;
683                                 case OciDataType.Clob:
684                                         if (direction == ParameterDirection.Input) {
685                                                 svalue = v.ToString();
686                                                 rsize = 0;
687
688                                                 // Get size of buffer
689                                                 OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
690
691                                                 // Fill buffer
692                                                 bytes = new byte[rsize];
693                                                 OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
694
695                                                 bindType = OciDataType.Long;
696                                                 bindSize = bytes.Length;
697                                         } 
698                                         else if (direction == ParameterDirection.InputOutput) {
699                                                 // not the exact error that .net 2.0 throws, but this is better
700                                                 throw new NotImplementedException ("Parameters of OracleType.Clob with direction of InputOutput are not supported.");
701                                         }
702                                         else {
703                                                 // Output and Return parameters
704                                                 bindSize = -1;
705                                                 lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
706                                                 if (lobLocator == null) {
707                                                         OciErrorInfo info = connection.ErrorHandle.HandleError ();
708                                                         throw new OracleException (info.ErrorCode, info.ErrorMessage);
709                                                 }
710                                                 bindOutValue = lobLocator.Handle;
711                                                 bindValue = lobLocator.Handle;
712                                                 lobLocator.ErrorHandle = connection.ErrorHandle;
713                                                 lobLocator.Service = statement.Service;
714                                                 lobLocator.Environment = connection.Environment;
715                                                 useRef = true;
716                                         }
717                                         break;
718                                 case OciDataType.Blob:
719                                         if (direction == ParameterDirection.Input) {
720                                                 if (v is byte[]) {
721                                                         bytes = (byte[]) v;
722                                                         bindType = OciDataType.LongRaw;
723                                                         bindSize = bytes.Length;
724                                                 }
725                                                 else if (v is OracleLob) {
726                                                         OracleLob lob = (OracleLob) v;
727                                                         if (lob.LobType == OracleType.Blob) {
728                                                                 lobLocator = lob.Locator;
729                                                                 bindOutValue = lobLocator.Handle;
730                                                                 bindValue = lobLocator.Handle;
731                                                                 lobLocator.ErrorHandle = connection.ErrorHandle;
732                                                                 lobLocator.Service = connection.ServiceContext;
733                                                                 useRef = true;
734                                                         }
735                                                         else
736                                                                 throw new NotImplementedException("For OracleType.Blob, data type OracleLob of LobType Clob/NClob is not implemented.");
737                                                 }
738                                                 else
739                                                         throw new NotImplementedException ("For OracleType.Blob, data type not implemented: " + v.GetType().ToString()); // ?
740                                         }
741                                         else if (direction == ParameterDirection.InputOutput) {
742                                                 // not the exact error that .net 2.0 throws, but this is better
743                                                 throw new NotImplementedException ("Parameters of OracleType.Blob with direction of InputOutput are not supported.");
744                                         }
745                                         else {
746                                                 bindSize = -1;
747                                                 if (value != null && value is OracleLob) {
748                                                         OracleLob blob = (OracleLob) value;
749                                                         if (blob.LobType == OracleType.Blob)
750                                                                 if (value != OracleLob.Null) {
751                                                                         lobLocator = blob.Locator;
752                                                                         byte[] bs = (byte[]) blob.Value;
753                                                                         bindSize = bs.Length;
754                                                                 }
755                                                 }
756                                                 if (lobLocator == null) {
757                                                         lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
758                                                         if (lobLocator == null) {
759                                                                 OciErrorInfo info = connection.ErrorHandle.HandleError ();
760                                                                 throw new OracleException (info.ErrorCode, info.ErrorMessage);
761                                                         }
762                                                 }
763                                                 bindOutValue = lobLocator.Handle;
764                                                 bindValue = lobLocator.Handle;
765                                                 lobLocator.ErrorHandle = connection.ErrorHandle;
766                                                 lobLocator.Service = connection.ServiceContext;
767                                                 lobLocator.Environment = connection.Environment;
768                                                 useRef = true;
769                                         }
770                                         break;
771                                 case OciDataType.Raw:
772                                 case OciDataType.VarRaw:
773                                         bindType = OciDataType.VarRaw;
774                                         bindSize = Size + 2; // include 2 bytes prepended to hold the length
775                                         Indicator = 0;
776                                         bytes = new byte [bindSize];
777                                         if (direction == ParameterDirection.Input || 
778                                                 direction == ParameterDirection.InputOutput) {
779                                                 byteCount = 0;
780                                                 byte[] val;
781                                                 if (dbType == DbType.Guid)
782                                                         val = ((Guid)v).ToByteArray();
783                                                 else
784                                                         val = v as byte[];
785                                                 if (val.Length > 0) {   
786                                                         byteCount = val.Length;
787                                                         // LONG VARRAW prepends a 4-byte length
788                                                         if (byteCount > 0) {
789                                                                 byteArrayLen = BitConverter.GetBytes ((ushort) byteCount);
790                                                                 bytes[0] = byteArrayLen[0];
791                                                                 bytes[1] = byteArrayLen[1];
792                                                                 Array.ConstrainedCopy (val, 0, bytes, 2, byteCount);
793                                                         }
794                                                 }
795                                         }
796                                         break;
797                                 case OciDataType.LongRaw:
798                                 case OciDataType.LongVarRaw:
799                                         bindType = OciDataType.LongVarRaw;
800                                         bindSize = Size + 4; // include 4 bytes prepended to hold the length
801                                         Indicator = 0;
802                                         bytes = new byte [bindSize];
803                                         if (direction == ParameterDirection.Input || 
804                                                 direction == ParameterDirection.InputOutput) {
805                                                 byteCount = 0;
806                                                 byte[] val = v as byte[];
807                                                 if (val.Length > 0) {   
808                                                         byteCount = val.Length;
809                                                         // LONG VARRAW prepends a 4-byte length
810                                                         if (byteCount > 0) {
811                                                                 byteArrayLen = BitConverter.GetBytes ((uint) byteCount);
812                                                                 bytes[0] = byteArrayLen[0];
813                                                                 bytes[1] = byteArrayLen[1];
814                                                                 bytes[2] = byteArrayLen[2];
815                                                                 bytes[3] = byteArrayLen[3];
816                                                                 Array.ConstrainedCopy (val, 0, bytes, 4, byteCount);
817                                                         }
818                                                 }
819                                         }
820                                         break;
821                                 case OciDataType.RowIdDescriptor:
822                                         if (direction == ParameterDirection.Output || 
823                                                 direction == ParameterDirection.InputOutput || 
824                                                 direction == ParameterDirection.ReturnValue) {
825
826                                         size = 10;
827                                         bindType = OciDataType.Char;
828                                         bindSize = size * 2;
829                                         bindOutValue = OciCalls.AllocateClear (bindSize);
830                                         bindValue = bindOutValue;
831                                         } else
832                                                 throw new NotImplementedException("data type RowIdDescriptor as Intput parameters");
833                                         break;
834                                 case OciDataType.RSet: // REF CURSOR
835                                         if (direction == ParameterDirection.Output || 
836                                                 direction == ParameterDirection.InputOutput || 
837                                                 direction == ParameterDirection.ReturnValue) {
838                                                 if (cursor != IntPtr.Zero) {
839                                                         OciCalls.OCIHandleFree (cursor,
840                                                                 OciHandleType.Statement);
841                                                         cursor = IntPtr.Zero;
842                                                 }
843                                                 OciCalls.OCIHandleAlloc (connection.Environment,
844                                                         out cursor,
845                                                         OciHandleType.Statement,
846                                                         0,
847                                                         IntPtr.Zero);
848                                                         bindSize = 0;
849                                                 bindType = OciDataType.RSet;
850                                         } else
851                                                 throw new NotImplementedException ("data type Ref Cursor not implemented for Input parameters");
852                                         break;
853                                 default:
854                                         throw new NotImplementedException ("Data Type not implemented: " + ociType.ToString() + ".");
855                                 }                       
856                         }
857                         
858                         // Now, call the appropriate OCI Bind function;
859
860                         if (useRef == true) {
861                                 if (bindType == OciDataType.TimeStamp) {
862                                         bindValue = dateTimeDesc.Handle;
863                                         status = OciCalls.OCIBindByNameRef (statement,
864                                                 out tmpHandle,
865                                                 connection.ErrorHandle,
866                                                 ParameterName,
867                                                 ParameterName.Length,
868                                                 ref bindValue,
869                                                 bindSize,
870                                                 bindType,
871                                                 indicator,
872                                                 IntPtr.Zero,
873                                                 IntPtr.Zero,
874                                                 0,
875                                                 IntPtr.Zero,
876                                                 0);
877                                 }
878                                 else {
879                                         status = OciCalls.OCIBindByNameRef (statement,
880                                                 out tmpHandle,
881                                                 connection.ErrorHandle,
882                                                 ParameterName,
883                                                 ParameterName.Length,
884                                                 ref bindValue,
885                                                 bindSize,
886                                                 bindType,
887                                                 indicator,
888                                                 IntPtr.Zero,
889                                                 IntPtr.Zero,
890                                                 0,
891                                                 IntPtr.Zero,
892                                                 0);
893                                 }
894                         }
895                         else if (bindType == OciDataType.RSet) {
896                                 status = OciCalls.OCIBindByNameRef (statement,
897                                         out tmpHandle,
898                                         connection.ErrorHandle,
899                                         ParameterName,
900                                         ParameterName.Length,
901                                         ref cursor,
902                                         bindSize,
903                                         bindType,
904                                         indicator,
905                                         IntPtr.Zero,
906                                         IntPtr.Zero,
907                                         0,
908                                         IntPtr.Zero,
909                                         0);
910                         }
911                         else if (bytes != null) {
912                                 status = OciCalls.OCIBindByNameBytes (statement,
913                                         out tmpHandle,
914                                         connection.ErrorHandle,
915                                         ParameterName,
916                                         ParameterName.Length,
917                                         bytes,
918                                         bindSize,
919                                         bindType,
920                                         indicator,
921                                         IntPtr.Zero,
922                                         IntPtr.Zero,
923                                         0,
924                                         IntPtr.Zero,
925                                         0);
926                         }
927                         else {
928                                 status = OciCalls.OCIBindByName (statement,
929                                         out tmpHandle,
930                                         connection.ErrorHandle,
931                                         ParameterName,
932                                         ParameterName.Length, // FIXME: this should be in bytes!
933                                         bindValue,
934                                         bindSize,
935                                         bindType,
936                                         indicator,
937                                         IntPtr.Zero,
938                                         IntPtr.Zero,
939                                         0,
940                                         IntPtr.Zero,
941                                         0);
942                         }
943                         OciErrorHandle.ThrowExceptionIfError (connection.ErrorHandle, status);
944
945                         bindHandle.SetHandle (tmpHandle);
946                 }
947
948                 object ICloneable.Clone ()
949                 {
950                         return new OracleParameter(this);
951                 }
952
953                 private void InferOracleType (object value)
954                 {
955                         // Should we throw an exception here?
956                         if (value == null || value == DBNull.Value)
957                                 return;
958                         
959                         Type type = value.GetType ();
960                         string exception = String.Format ("The parameter data type of {0} is invalid.", type.FullName);
961                         switch (type.FullName) {
962                         case "System.Int64":
963                                 SetOracleType (OracleType.Number, true);
964                                 break;
965                         case "System.Boolean":
966                         case "System.Byte":
967                                 SetOracleType (OracleType.Byte, true);
968                                 break;
969                         case "System.String":
970                         case "System.Data.OracleClient.OracleString":
971                                 SetOracleType (OracleType.VarChar, true);
972                                 break;
973                         case "System.Data.OracleClient.OracleDateTime":
974                         case "System.DateTime":
975                                 SetOracleType (OracleType.DateTime, true);
976                                 break;
977                         case "System.Decimal":
978                         case "System.Data.OracleClient.OracleNumber":
979                                 SetOracleType (OracleType.Number, true);
980                                 break;
981                         case "System.Double":
982                                 SetOracleType (OracleType.Double, true);
983                                 break;
984                         case "System.Byte[]":
985                         case "System.Guid":
986                                 SetOracleType (OracleType.Raw, true);
987                                 break;
988                         case "System.Int32":
989                                 SetOracleType (OracleType.Int32, true);
990                                 break;
991                         case "System.Single":
992                                 SetOracleType (OracleType.Float, true);
993                                 break;
994                         case "System.Int16":
995                                 SetOracleType (OracleType.Int16, true);
996                                 break;
997                         case "System.DBNull":
998                                 break; //unable to guess type
999                         case "System.Data.OracleClient.OracleLob":
1000                                 SetOracleType (((OracleLob) value).LobType, true); 
1001                                 break;
1002                         default:
1003                                 throw new ArgumentException (exception);
1004                         }
1005                 }
1006
1007                 private int InferSize ()
1008                 {
1009                         int newSize = 0;
1010
1011                         switch (ociType) {
1012                         case OciDataType.VarChar2:
1013                         case OciDataType.String:
1014                         case OciDataType.VarChar:
1015                         case OciDataType.Char:
1016                         case OciDataType.CharZ:
1017                         case OciDataType.OciString:
1018                         case OciDataType.Long:
1019                         case OciDataType.LongVarChar:
1020                                 if (sizeManuallySet == true)
1021                                         return size;
1022                                 if (value == null || value == DBNull.Value)
1023                                         newSize = 0;
1024                                 else
1025                                         newSize = value.ToString ().Length;
1026                                 break;
1027                         case OciDataType.RowIdDescriptor:
1028                                 newSize = 10;
1029                                 break;
1030                         case OciDataType.Integer:
1031                         case OciDataType.Number:
1032                         case OciDataType.Float:
1033                                 newSize = 22;
1034                                 break;
1035                         case OciDataType.Date:
1036                                 newSize = 7;
1037                                 break;
1038                         case OciDataType.TimeStamp:
1039                                 newSize = 11;
1040                                 break;
1041                         case OciDataType.Blob:
1042                         case OciDataType.Clob:
1043                         case OciDataType.RSet: // REF CURSOR
1044                                 newSize = -1;
1045                                 break;
1046                         case OciDataType.Raw:
1047                                 if (dbType == DbType.Guid)
1048                                         newSize = ((Guid)value).ToByteArray().Length;
1049                                 else
1050                                         newSize = (value as byte[]).Length;
1051                                 break;
1052                         default:
1053                                 if (value == null || value == DBNull.Value)
1054                                         newSize = 0;
1055                                 else
1056                                         newSize = value.ToString ().Length;
1057                                 break;
1058                         }
1059
1060                         sizeSet = true;
1061
1062                         return newSize;
1063                 }
1064
1065                 private void SetDbType (DbType type)
1066                 {
1067                         string exception = String.Format ("No mapping exists from DbType {0} to a known OracleType.", type);
1068                         switch (type) {
1069                         case DbType.AnsiString:
1070                                 oracleType = OracleType.VarChar;
1071                                 ociType = OciDataType.VarChar;
1072                                 break;
1073                         case DbType.AnsiStringFixedLength:
1074                                 oracleType = OracleType.Char;
1075                                 ociType = OciDataType.Char;
1076                                 break;
1077                         case DbType.Binary:
1078                         case DbType.Guid:
1079                                 oracleType = OracleType.Raw;
1080                                 ociType = OciDataType.Raw;
1081                                 break;
1082                         case DbType.Boolean:
1083                         case DbType.Byte:
1084                                 oracleType = OracleType.Byte;
1085                                 ociType = OciDataType.Integer;
1086                                 break;
1087                         case DbType.Currency:
1088                         case DbType.Decimal:
1089                         case DbType.Int64:
1090                                 oracleType = OracleType.Number;
1091                                 ociType = OciDataType.Number;
1092                                 break;
1093                         case DbType.Date:
1094                         case DbType.DateTime:
1095                         case DbType.Time:
1096                                 oracleType = OracleType.DateTime;
1097                                 ociType = OciDataType.Char;
1098                                 break;
1099                         case DbType.Double:
1100                                 oracleType = OracleType.Double;
1101                                 ociType = OciDataType.Float;
1102                                 break;
1103                         case DbType.Int16:
1104                                 oracleType = OracleType.Int16;
1105                                 ociType = OciDataType.Integer;
1106                                 break;
1107                         case DbType.Int32:
1108                                 oracleType = OracleType.Int32;
1109                                 ociType = OciDataType.Integer;
1110                                 break;
1111                         case DbType.Object:
1112                                 oracleType = OracleType.Blob;
1113                                 ociType = OciDataType.Blob;
1114                                 break;
1115                         case DbType.Single:
1116                                 oracleType = OracleType.Float;
1117                                 ociType = OciDataType.Float;
1118                                 break;
1119                         case DbType.String:
1120                                 oracleType = OracleType.NVarChar;
1121                                 ociType = OciDataType.VarChar;
1122                                 break;
1123                         case DbType.StringFixedLength:
1124                                 oracleType = OracleType.NChar;
1125                                 ociType = OciDataType.Char;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
1126
1127                                 break;
1128                         default:
1129                                 throw new ArgumentException (exception);
1130                         }
1131                         dbType = type;
1132                 }
1133
1134                 private void SetOracleType (OracleType type, bool inferring)
1135                 {
1136                         Type valType;
1137                         FreeHandle ();
1138
1139                         if (value == null)
1140                                 valType = typeof(System.DBNull);
1141                         else
1142                                 valType = value.GetType ();
1143
1144                         string exception = String.Format ("No mapping exists from OracleType {0} to a known DbType.", type);
1145                         switch (type) {
1146                         case OracleType.BFile:
1147                         case OracleType.Blob:
1148                                 dbType = DbType.Binary;
1149                                 ociType = OciDataType.Blob;
1150                                 break;
1151                         case OracleType.LongRaw:
1152                         case OracleType.Raw:
1153                                 if (valType.FullName == "System.Guid")
1154                                         dbType = DbType.Guid;
1155                                 else
1156                                         dbType = DbType.Binary;
1157                                 ociType = OciDataType.Raw;
1158                                 break;
1159                         case OracleType.Byte:
1160                                 dbType = DbType.Byte;
1161                                 ociType = OciDataType.Number;
1162                                 break;
1163                         case OracleType.Char:
1164                                 dbType = DbType.AnsiString;
1165                                 ociType = OciDataType.Char;
1166                                 break;
1167                         case OracleType.Clob:
1168                                 dbType = DbType.AnsiString;
1169                                 ociType = OciDataType.Clob;
1170                                 break;
1171                         case OracleType.LongVarChar:
1172                         case OracleType.RowId:
1173                         case OracleType.VarChar:
1174                                 dbType = DbType.AnsiString;
1175                                 ociType = OciDataType.VarChar;
1176                                 break;
1177                         case OracleType.Cursor: // REF CURSOR
1178                                 ociType = OciDataType.RSet;
1179                                 dbType = DbType.Object;
1180                                 break;
1181                         case OracleType.IntervalDayToSecond:
1182                                 dbType = DbType.AnsiStringFixedLength;
1183                                 ociType = OciDataType.Char;
1184                                 break;
1185                         case OracleType.Timestamp:
1186                         case OracleType.TimestampLocal:
1187                         case OracleType.TimestampWithTZ:
1188                                 dbType = DbType.DateTime;
1189                                 ociType = OciDataType.TimeStamp;
1190                                 break;
1191                         case OracleType.DateTime:
1192                                 dbType = DbType.DateTime;
1193                                 ociType = OciDataType.Date;
1194                                 break;
1195                         case OracleType.Double:
1196                                 dbType = DbType.Double;
1197                                 ociType = OciDataType.Number;
1198                                 break;
1199                         case OracleType.Float:
1200                                 dbType = DbType.Single;
1201                                 ociType = OciDataType.Number;
1202                                 break;
1203                         case OracleType.Int16:
1204                                 dbType = DbType.Int16;
1205                                 ociType = OciDataType.Number;
1206                                 break;
1207                         case OracleType.Int32:
1208                         case OracleType.IntervalYearToMonth:
1209                                 dbType = DbType.Int32;
1210                                 ociType = OciDataType.Number;
1211                                 break;
1212                         case OracleType.NChar:
1213                                 dbType = DbType.StringFixedLength;
1214                                 ociType = OciDataType.Char;
1215                                 break;
1216                         case OracleType.NClob:
1217                         case OracleType.NVarChar:
1218                                 dbType = DbType.String;
1219                                 ociType = OciDataType.Char;
1220                                 break;
1221                         case OracleType.Number:
1222                                 dbType = DbType.VarNumeric;
1223                                 ociType = OciDataType.Number;
1224                                 break;
1225                         case OracleType.SByte:
1226                                 dbType = DbType.SByte;
1227                                 ociType = OciDataType.Number;
1228                                 break;
1229                         case OracleType.UInt16:
1230                                 dbType = DbType.UInt16;
1231                                 ociType = OciDataType.Number;
1232                                 break;
1233                         case OracleType.UInt32:
1234                                 dbType = DbType.UInt32;
1235                                 ociType = OciDataType.Number;
1236                                 break;
1237                         default:
1238                                 throw new ArgumentException (exception);
1239                         }
1240
1241                         if (!oracleTypeSet || !inferring )
1242                                 oracleType = type;
1243                 }
1244
1245 #if NET_2_0
1246                 public override void ResetDbType ()
1247                 {
1248                         ResetOracleType ();
1249                 }
1250
1251                 public void ResetOracleType ()
1252                 {
1253                         oracleTypeSet = false;
1254                         InferOracleType (value);
1255                 }
1256 #endif // NET_2_0
1257
1258                 public override string ToString ()
1259                 {
1260                         return ParameterName;
1261                 }
1262
1263                 private void GetOutValue (OracleCommand cmd)
1264                 {
1265                         // used to update the parameter value
1266                         // for Output, the output of InputOutput, and Return parameters
1267                         value = DBNull.Value;
1268                         if (Indicator == -1)
1269                                 return;
1270
1271                         int rsize = 0;
1272                         IntPtr env = IntPtr.Zero;
1273                         StringBuilder ret = null;
1274
1275                         // FIXME: redo all types - see how Char, Number, and Date are done
1276                         // here and in Bind()
1277
1278                         switch (ociType) {
1279                         case OciDataType.VarChar2:
1280                         case OciDataType.String:
1281                         case OciDataType.VarChar:
1282                         case OciDataType.Char:
1283                         case OciDataType.CharZ:
1284                         case OciDataType.OciString:
1285                         case OciDataType.RowIdDescriptor:
1286                                 // Get length of returned string
1287                                 rsize = 0;
1288                                 env = cmd.Connection.Environment;
1289                                 OciCalls.OCICharSetToUnicode (env, null, bytes, out rsize);
1290
1291                                 // Get string
1292                                 ret = new StringBuilder(rsize);
1293                                 OciCalls.OCICharSetToUnicode (env, ret, bytes, out rsize);
1294
1295                                 value = ret.ToString ();
1296                                 break;
1297                         case OciDataType.Long:
1298                         case OciDataType.LongVarChar:
1299                                 int longSize = 0;
1300                                 if (BitConverter.IsLittleEndian)
1301                                         longSize = BitConverter.ToInt32 (new byte [] {bytes [0], bytes [1], bytes [2], bytes [3]}, 0);
1302                                 else
1303                                         longSize = BitConverter.ToInt32 (new byte [] {bytes [3], bytes [2], bytes [1], bytes [0]}, 0);
1304
1305                                 ASCIIEncoding encoding = new ASCIIEncoding ();
1306                                 value = encoding.GetString (bytes, 4, longSize);
1307                                 encoding = null;
1308                                 break;
1309                         case OciDataType.LongRaw:
1310                         case OciDataType.LongVarRaw:
1311                                 int longrawSize = 0;
1312                                 if (BitConverter.IsLittleEndian)
1313                                         longrawSize = BitConverter.ToInt32 (new byte [] {bytes [0], bytes [1], bytes [2], bytes [3]}, 0);
1314                                 else
1315                                         longrawSize = BitConverter.ToInt32 (new byte [] {bytes [3], bytes [2], bytes [1], bytes [0]}, 0);
1316
1317                                 byte[] longraw_buffer = new byte [longrawSize];
1318                                 Array.ConstrainedCopy (bytes, 4, longraw_buffer, 0, longrawSize);
1319                                 value = longraw_buffer;
1320                                 break;
1321                         case OciDataType.Raw:
1322                         case OciDataType.VarRaw:
1323                                 int rawSize = 0;
1324                                 if (BitConverter.IsLittleEndian)
1325                                         rawSize = (int) BitConverter.ToInt16 (new byte [] {bytes [0], bytes [1]}, 0);
1326                                 else
1327                                         rawSize = (int) BitConverter.ToInt16 (new byte [] {bytes [1], bytes [0]}, 0);
1328
1329                                 byte[] raw_buffer = new byte [rawSize];
1330                                 Array.ConstrainedCopy (bytes, 2, raw_buffer, 0, rawSize);
1331                                 value = raw_buffer;
1332                                 break;
1333                         case OciDataType.Integer:
1334                         case OciDataType.Number:
1335                         case OciDataType.Float:
1336                                 rsize = 0;
1337                                 env = cmd.Connection.Environment;
1338                                 OciCalls.OCICharSetToUnicode (env, null, bytes, out rsize);
1339
1340                                 // Get string
1341                                 ret = new StringBuilder(rsize);
1342                                 OciCalls.OCICharSetToUnicode (env, ret, bytes, out rsize);
1343
1344                                 // if not empty, parse string as a decimal using session format
1345                                 if (ret.Length > 0) {
1346                                         switch (dbType) {
1347                                         case DbType.UInt16: 
1348                                                 value = UInt16.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1349                                                 break;
1350                                         case DbType.UInt32: 
1351                                                 value = UInt32.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1352                                                 break;
1353                                         case DbType.Int16:
1354                                                 value = Int16.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1355                                                 break;                                                  
1356                                         case DbType.Int32:
1357                                                 value = Int32.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1358                                                 break;
1359                                         default:
1360                                                 value = Decimal.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1361                                                 break;
1362                                         }
1363                                 }
1364                                 break;
1365                         case OciDataType.TimeStamp:
1366                                 value = dateTimeDesc.GetDateTime (connection.Environment, dateTimeDesc.ErrorHandle);
1367                                 break;
1368                         case OciDataType.Date:
1369                                 value = UnpackDate (bytes);
1370                                 break;
1371                         case OciDataType.Blob:
1372                         case OciDataType.Clob:
1373                                 if (value != null && value is OracleLob && value != OracleLob.Null) {
1374                                         OracleLob lob2 = (OracleLob) value;
1375                                         lob2.connection = connection;
1376                                 }
1377                                 else {
1378                                         OracleLob lob = new OracleLob (lobLocator, ociType);
1379                                         lob.connection = connection;
1380                                         value = lob;
1381                                 }
1382                                 break;
1383                         case OciDataType.RSet: // REF CURSOR                            
1384                                 OciStatementHandle cursorStatement = GetOutRefCursor (cmd);
1385                                 value = new OracleDataReader (cursorStatement.Command, cursorStatement, true, CommandBehavior.Default);
1386                                 break;
1387                         default:
1388                                 throw new NotImplementedException ("Data Type not implemented: " + ociType.ToString() + ".");
1389                         }
1390                 }
1391
1392                 internal OciStatementHandle GetOutRefCursor (OracleCommand cmd) 
1393                 {
1394                                 OciStatementHandle cursorStatement = new OciStatementHandle (cmd.Connection.ServiceContext, cursor);
1395
1396                                 cursorStatement.ErrorHandle = cmd.ErrorHandle;
1397                                 cursorStatement.Command = cmd;
1398                                 cursorStatement.SetupRefCursorResult (cmd.Connection);
1399                                 cursorStatement.Service = cmd.Connection.ServiceContext;
1400                                 cursor = IntPtr.Zero;
1401                                 return cursorStatement;                 
1402                 }
1403
1404                 internal void Update (OracleCommand cmd)
1405                 {
1406                         if (Direction != ParameterDirection.Input)
1407                                 GetOutValue (cmd);
1408
1409                         FreeHandle ();
1410                 }
1411
1412                 internal void FreeHandle ()
1413                 {
1414                         switch (ociType) {
1415                         case OciDataType.Clob:
1416                         case OciDataType.Blob:
1417                                 lobLocator = null;
1418                                 break;
1419                         case OciDataType.TimeStamp:
1420                                 break;
1421                         default:
1422                                 Marshal.FreeHGlobal (bindOutValue);
1423                                 break;
1424                         }
1425
1426                         bindOutValue = IntPtr.Zero;
1427                         bindValue = IntPtr.Zero;
1428
1429                         bindHandle = null;
1430                         connection = null;
1431                 }
1432
1433                 // copied from OciDefineHandle
1434                 [MonoTODO ("Be able to handle negative dates... i.e. BCE.")]
1435                 private DateTime UnpackDate (byte[] bytes)
1436                 {
1437                         byte century = bytes [0];
1438                         byte year    = bytes [1];
1439                         byte month   = bytes [2];
1440                         byte day     = bytes [3];
1441                         byte hour    = bytes [4];
1442                         byte minute  = bytes [5];
1443                         byte second  = bytes [6];
1444
1445
1446                         return new DateTime ((century - 100) * 100 + (year - 100),
1447                                                 month,
1448                                                 day,
1449                                                 hour - 1,
1450                                                 minute - 1,
1451                                                 second - 1);
1452
1453                 }
1454
1455                 private byte[] PackDate (DateTime dateValue)
1456                 {
1457                         byte[] buffer = new byte[7];
1458
1459                         buffer[0] = (byte)((dateValue.Year / 100) + 100); //century
1460                         buffer[1] = (byte)((dateValue.Year % 100) + 100); // Year
1461                         buffer[2] = (byte)dateValue.Month;
1462                         buffer[3] = (byte)dateValue.Day;
1463                         buffer[4] = (byte)(dateValue.Hour+1);
1464                         buffer[5] = (byte)(dateValue.Minute+1);
1465                         buffer[6] = (byte)(dateValue.Second+1);
1466
1467                         return buffer;
1468                 }
1469
1470                 public void Dispose ()
1471                 {
1472                         Dispose (true);
1473                 }
1474
1475                 void Dispose (bool disposing) 
1476                 {
1477                         if (disposing) {
1478                                 GC.SuppressFinalize(this);
1479                         }
1480                         if (indicator != IntPtr.Zero) {
1481                                 Marshal.FreeHGlobal (indicator);
1482                                 indicator = IntPtr.Zero;
1483                         }
1484                 }
1485
1486                 #endregion // Methods
1487
1488                 internal sealed class OracleParameterConverter : ExpandableObjectConverter
1489                 {
1490                         public OracleParameterConverter ()
1491                         {
1492                         }
1493
1494                         [MonoTODO]
1495                         public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
1496                         {
1497                                 throw new NotImplementedException ();
1498                         }
1499
1500                         [MonoTODO]
1501                         public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
1502                         {
1503                                 throw new NotImplementedException ();
1504                         }
1505                 }
1506         }
1507 }