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