4 // Part of the Mono class libraries at
5 // mcs/class/System.Data.OracleClient/System.Data.OracleClient
7 // Assembly: System.Data.OracleClient.dll
8 // Namespace: System.Data.OracleClient
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>
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
21 // Licensed under the MIT/X11 License.
25 using System.Collections;
26 using System.ComponentModel;
29 using System.Data.Common;
31 using System.Data.SqlTypes;
32 using System.Data.OracleClient.Oci;
33 using System.Globalization;
34 using System.Runtime.InteropServices;
37 namespace System.Data.OracleClient
39 [TypeConverter (typeof(OracleParameter.OracleParameterConverter))]
40 public sealed class OracleParameter :
42 DbParameter, IDbDataParameter, ICloneable,
44 MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable,
51 OracleType oracleType = OracleType.VarChar;
54 ParameterDirection direction = ParameterDirection.Input;
60 bool sourceColumnNullMapping;
62 DataRowVersion srcVersion;
63 DbType dbType = DbType.AnsiString;
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;
74 OracleParameterCollection container;
75 OciBindHandle bindHandle;
76 OracleConnection connection;
78 IntPtr bindValue = IntPtr.Zero;
89 // constructor for cloning the object
90 private OracleParameter (OracleParameter value)
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));
111 public OracleParameter ()
113 this.name = String.Empty;
114 this.oracleType = OracleType.VarChar;
116 this.direction = ParameterDirection.Input;
117 this.isNullable = false;
120 this.srcColumn = String.Empty;
121 this.srcVersion = DataRowVersion.Current;
123 this.oracleTypeSet = false;
124 this.indicator = OciCalls.AllocateClear (sizeof(short));
127 public OracleParameter (string name, object value)
132 srcColumn = string.Empty;
133 SourceVersion = DataRowVersion.Current;
134 InferOracleType (value);
135 this.indicator = OciCalls.AllocateClear (sizeof(short));
137 // Find the OciType before inferring for the size
138 if (value != null && value != DBNull.Value) {
140 this.size = InferSize ();
145 public OracleParameter (string name, OracleType oracleType)
146 : this (name, oracleType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
150 public OracleParameter (string name, OracleType oracleType, int size)
151 : this (name, oracleType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
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)
161 public OracleParameter (string name, OracleType oracleType, int size, ParameterDirection direction, string sourceColumn, DataRowVersion sourceVersion, bool sourceColumnNullMapping, object value)
165 throw new ArgumentException("Size must be not be negative.");
169 Direction = direction;
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) &&
176 SourceColumnNullMapping = sourceColumnNullMapping;
177 OracleType = oracleType;
178 SourceColumn = sourceColumn;
179 SourceVersion = sourceVersion;
180 this.indicator = OciCalls.AllocateClear (sizeof(short));
184 public OracleParameter (string name, OracleType oracleType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string srcColumn, DataRowVersion srcVersion, object value)
188 throw new ArgumentException("Size must be not be negative.");
193 Direction = direction;
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) &&
200 this.isNullable = isNullable;
201 this.precision = precision;
204 OracleType = oracleType;
205 SourceColumn = srcColumn;
206 SourceVersion = srcVersion;
207 this.indicator = OciCalls.AllocateClear (sizeof(short));
215 #endregion // Constructors
219 internal OracleParameterCollection Container {
220 get { return container; }
221 set { container = value; }
224 internal short Indicator {
225 get { return (Marshal.ReadInt16(indicator)); }
226 set { Marshal.WriteInt16(indicator, value); }
231 [RefreshProperties (RefreshProperties.All)]
232 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
239 get { return dbType; }
240 set { SetDbType (value); }
244 [DefaultValue (ParameterDirection.Input)]
246 [RefreshProperties (RefreshProperties.All)]
251 ParameterDirection Direction {
252 get { return direction; }
255 if (this.size > 0 && direction == ParameterDirection.Output)
263 [DefaultValue (false)]
264 [EditorBrowsable (EditorBrowsableState.Never)]
271 get { return isNullable; }
272 set { isNullable = value; }
276 [EditorBrowsable (EditorBrowsableState.Advanced)]
282 get { return offset; }
283 set { offset = value; }
286 [DefaultValue (OracleType.VarChar)]
287 [RefreshProperties (RefreshProperties.All)]
289 [DbProviderSpecificTypeProperty (true)]
291 public OracleType OracleType {
292 get { return oracleType; }
294 oracleTypeSet = true;
295 SetOracleType (value, false);
306 string ParameterName {
312 set { name = value; }
317 [EditorBrowsable (EditorBrowsableState.Never)]
318 [Obsolete("Set the precision of a decimal use the Math classes.")]
322 public byte Precision {
323 get { return precision; }
324 set { /* NO EFFECT*/ }
329 [EditorBrowsable (EditorBrowsableState.Never)]
330 [Obsolete("Set the precision of a decimal use the Math classes.")]
335 get { return scale; }
336 set { /* NO EFFECT*/ }
351 sizeManuallySet = true;
362 string SourceColumn {
363 get { return srcColumn; }
364 set { srcColumn = value; }
369 public override bool SourceColumnNullMapping {
370 get { return sourceColumnNullMapping; }
371 set { sourceColumnNullMapping = value; }
376 [DefaultValue ("Current")]
382 DataRowVersion SourceVersion {
383 get { return srcVersion; }
384 set { srcVersion = value; }
388 [DefaultValue (null)]
390 [RefreshProperties (RefreshProperties.All)]
391 [TypeConverter (typeof(StringConverter))]
397 get { return this.value; }
401 InferOracleType (value);
403 if (value != null && value != DBNull.Value) {
404 this.size = InferSize ();
411 #endregion // Properties
415 private void AssertSizeIsSet ()
418 case OciDataType.VarChar2:
419 case OciDataType.String:
420 case OciDataType.VarChar:
421 case OciDataType.Char:
422 case OciDataType.CharZ:
423 case OciDataType.OciString:
425 throw new Exception ("Size must be set.");
432 internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos)
436 if (bindHandle == null)
437 bindHandle = new OciBindHandle ((OciHandle) statement);
439 IntPtr tmpHandle = bindHandle.Handle;
441 if (Direction != ParameterDirection.Input)
459 if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) {
462 else if (v is DBNull)
465 INullable mynullable = v as INullable;
466 if (mynullable != null)
467 isnull = mynullable.IsNull;
471 if (isnull == true && direction == ParameterDirection.Input) {
472 bindType = OciDataType.VarChar2;
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;
484 // convert value from managed type to type to marshal
485 if (direction == ParameterDirection.Input ||
486 direction == ParameterDirection.InputOutput) {
488 svalue = v.ToString ();
490 if (direction == ParameterDirection.Input && size > 0 && svalue.Length > size)
491 svalue = svalue.Substring(0, size);
493 svalue = svalue.ToString () + '\0';
495 // convert managed type to memory allocated earlier
496 // in this case using OCIUnicodeToCharSet
498 // Get size of buffer
499 status = OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
501 if (direction == ParameterDirection.Input)
504 // this cannot be rsize because you need room for the output after the execute
505 bindSize = Encoding.UTF8.GetMaxByteCount (Size + 1);
508 // allocate memory based on bind size
509 bytes = new byte [bindSize];
512 status = OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
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];
520 case OciDataType.Date:
521 bindType = OciDataType.Date;
523 // convert value from managed type to type to marshal
524 if (direction == ParameterDirection.Input ||
525 direction == ParameterDirection.InputOutput) {
528 bytes = new byte [7];
531 dt = DateTime.MinValue;
534 dt = DateTime.Parse (sDate);
536 else if (v is DateTime)
538 else if (v is OracleString) {
539 sDate = v.ToString ();
540 dt = DateTime.Parse (sDate);
542 else if (v is OracleDateTime) {
543 OracleDateTime odt = (OracleDateTime) v;
544 dt = (DateTime) odt.Value;
547 throw new NotImplementedException ("For OracleType.DateTime, data type not implemented: " + v.GetType().ToString() + ".");
549 // for Input and InputOuput, create byte array and pack DateTime into it
550 bytes = PackDate (dt);
553 // allocate 7-byte array for Output and ReturnValue to put date
554 bytes = new byte [7];
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);
563 dateTimeDesc.ErrorHandle = connection.ErrorHandle;
565 bindType = OciDataType.TimeStamp;
566 bindOutValue = dateTimeDesc.Handle;
567 bindValue = dateTimeDesc.Handle;
569 if (direction == ParameterDirection.Input ||
570 direction == ParameterDirection.InputOutput) {
572 dt = DateTime.MinValue;
576 else if (v is String) {
578 dt = DateTime.Parse (sDate);
580 else if (v is DateTime)
582 else if (v is OracleString) {
584 dt = DateTime.Parse (sDate);
586 else if (v is OracleDateTime) {
587 OracleDateTime odt = (OracleDateTime) v;
588 dt = (DateTime) odt.Value;
591 throw new NotImplementedException ("For OracleType.Timestamp, data type not implemented: " + v.GetType().ToString()); // ?
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,
607 case OciDataType.Integer:
608 case OciDataType.Float:
609 case OciDataType.Number:
610 bindType = OciDataType.String;
613 // convert value from managed type to type to marshal
614 if (direction == ParameterDirection.Input ||
615 direction == ParameterDirection.InputOutput) {
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);
623 svalue = v.ToString();
625 svalue = svalue + "\0";
628 // Get size of buffer
629 OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
633 if (direction == ParameterDirection.Input)
636 bindSize = 30; // need room for output possibly being bigger than the input
638 bytes = new byte [bindSize];
639 OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
641 // Output and ReturnValue parameters allocate memory
643 bytes = new byte [bindSize];
646 case OciDataType.Long:
647 case OciDataType.LongVarChar:
648 bindType = OciDataType.LongVarChar;
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
653 bindSize = Size + 5; // 4 bytes prepended for length, bytes, 1 byte NUL character
657 // convert value from managed type to type to marshal
658 if (direction == ParameterDirection.Input ||
659 direction == ParameterDirection.InputOutput) {
661 svalue = v.ToString () + '\0';
664 bytes = new byte [bindSize];
666 ASCIIEncoding enc = new ASCIIEncoding ();
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
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];
683 case OciDataType.Clob:
684 if (direction == ParameterDirection.Input) {
685 svalue = v.ToString();
688 // Get size of buffer
689 OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
692 bytes = new byte[rsize];
693 OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
695 bindType = OciDataType.Long;
696 bindSize = bytes.Length;
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.");
703 // Output and Return parameters
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);
710 bindOutValue = lobLocator.Handle;
711 bindValue = lobLocator.Handle;
712 lobLocator.ErrorHandle = connection.ErrorHandle;
713 lobLocator.Service = statement.Service;
714 lobLocator.Environment = connection.Environment;
718 case OciDataType.Blob:
719 if (direction == ParameterDirection.Input) {
722 bindType = OciDataType.LongRaw;
723 bindSize = bytes.Length;
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;
736 throw new NotImplementedException("For OracleType.Blob, data type OracleLob of LobType Clob/NClob is not implemented.");
739 throw new NotImplementedException ("For OracleType.Blob, data type not implemented: " + v.GetType().ToString()); // ?
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.");
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;
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);
763 bindOutValue = lobLocator.Handle;
764 bindValue = lobLocator.Handle;
765 lobLocator.ErrorHandle = connection.ErrorHandle;
766 lobLocator.Service = connection.ServiceContext;
767 lobLocator.Environment = connection.Environment;
771 case OciDataType.Raw:
772 case OciDataType.VarRaw:
773 bindType = OciDataType.VarRaw;
774 bindSize = Size + 2; // include 2 bytes prepended to hold the length
776 bytes = new byte [bindSize];
777 if (direction == ParameterDirection.Input ||
778 direction == ParameterDirection.InputOutput) {
781 if (dbType == DbType.Guid)
782 val = ((Guid)v).ToByteArray();
785 if (val.Length > 0) {
786 byteCount = val.Length;
787 // LONG VARRAW prepends a 4-byte length
789 byteArrayLen = BitConverter.GetBytes ((ushort) byteCount);
790 bytes[0] = byteArrayLen[0];
791 bytes[1] = byteArrayLen[1];
792 Array.ConstrainedCopy (val, 0, bytes, 2, byteCount);
797 case OciDataType.LongRaw:
798 case OciDataType.LongVarRaw:
799 bindType = OciDataType.LongVarRaw;
800 bindSize = Size + 4; // include 4 bytes prepended to hold the length
802 bytes = new byte [bindSize];
803 if (direction == ParameterDirection.Input ||
804 direction == ParameterDirection.InputOutput) {
806 byte[] val = v as byte[];
807 if (val.Length > 0) {
808 byteCount = val.Length;
809 // LONG VARRAW prepends a 4-byte length
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);
821 case OciDataType.RowIdDescriptor:
822 if (direction == ParameterDirection.Output ||
823 direction == ParameterDirection.InputOutput ||
824 direction == ParameterDirection.ReturnValue) {
827 bindType = OciDataType.Char;
829 bindOutValue = OciCalls.AllocateClear (bindSize);
830 bindValue = bindOutValue;
832 throw new NotImplementedException("data type RowIdDescriptor as Intput parameters");
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;
843 OciCalls.OCIHandleAlloc (connection.Environment,
845 OciHandleType.Statement,
849 bindType = OciDataType.RSet;
851 throw new NotImplementedException ("data type Ref Cursor not implemented for Input parameters");
854 throw new NotImplementedException ("Data Type not implemented: " + ociType.ToString() + ".");
858 // Now, call the appropriate OCI Bind function;
860 if (useRef == true) {
861 if (bindType == OciDataType.TimeStamp) {
862 bindValue = dateTimeDesc.Handle;
863 status = OciCalls.OCIBindByNameRef (statement,
865 connection.ErrorHandle,
867 ParameterName.Length,
879 status = OciCalls.OCIBindByNameRef (statement,
881 connection.ErrorHandle,
883 ParameterName.Length,
895 else if (bindType == OciDataType.RSet) {
896 status = OciCalls.OCIBindByNameRef (statement,
898 connection.ErrorHandle,
900 ParameterName.Length,
911 else if (bytes != null) {
912 status = OciCalls.OCIBindByNameBytes (statement,
914 connection.ErrorHandle,
916 ParameterName.Length,
928 status = OciCalls.OCIBindByName (statement,
930 connection.ErrorHandle,
932 ParameterName.Length, // FIXME: this should be in bytes!
943 OciErrorHandle.ThrowExceptionIfError (connection.ErrorHandle, status);
945 bindHandle.SetHandle (tmpHandle);
948 object ICloneable.Clone ()
950 return new OracleParameter(this);
953 private void InferOracleType (object value)
955 // Should we throw an exception here?
956 if (value == null || value == DBNull.Value)
959 Type type = value.GetType ();
960 string exception = String.Format ("The parameter data type of {0} is invalid.", type.FullName);
961 switch (type.FullName) {
963 SetOracleType (OracleType.Number, true);
965 case "System.Boolean":
967 SetOracleType (OracleType.Byte, true);
969 case "System.String":
970 case "System.Data.OracleClient.OracleString":
971 SetOracleType (OracleType.VarChar, true);
973 case "System.Data.OracleClient.OracleDateTime":
974 case "System.DateTime":
975 SetOracleType (OracleType.DateTime, true);
977 case "System.Decimal":
978 case "System.Data.OracleClient.OracleNumber":
979 SetOracleType (OracleType.Number, true);
981 case "System.Double":
982 SetOracleType (OracleType.Double, true);
984 case "System.Byte[]":
986 SetOracleType (OracleType.Raw, true);
989 SetOracleType (OracleType.Int32, true);
991 case "System.Single":
992 SetOracleType (OracleType.Float, true);
995 SetOracleType (OracleType.Int16, true);
997 case "System.DBNull":
998 break; //unable to guess type
999 case "System.Data.OracleClient.OracleLob":
1000 SetOracleType (((OracleLob) value).LobType, true);
1003 throw new ArgumentException (exception);
1007 private int InferSize ()
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)
1022 if (value == null || value == DBNull.Value)
1025 newSize = value.ToString ().Length;
1027 case OciDataType.RowIdDescriptor:
1030 case OciDataType.Integer:
1031 case OciDataType.Number:
1032 case OciDataType.Float:
1035 case OciDataType.Date:
1038 case OciDataType.TimeStamp:
1041 case OciDataType.Blob:
1042 case OciDataType.Clob:
1043 case OciDataType.RSet: // REF CURSOR
1046 case OciDataType.Raw:
1047 if (dbType == DbType.Guid)
1048 newSize = ((Guid)value).ToByteArray().Length;
1050 newSize = (value as byte[]).Length;
1053 if (value == null || value == DBNull.Value)
1056 newSize = value.ToString ().Length;
1065 private void SetDbType (DbType type)
1067 string exception = String.Format ("No mapping exists from DbType {0} to a known OracleType.", type);
1069 case DbType.AnsiString:
1070 oracleType = OracleType.VarChar;
1071 ociType = OciDataType.VarChar;
1073 case DbType.AnsiStringFixedLength:
1074 oracleType = OracleType.Char;
1075 ociType = OciDataType.Char;
1079 oracleType = OracleType.Raw;
1080 ociType = OciDataType.Raw;
1082 case DbType.Boolean:
1084 oracleType = OracleType.Byte;
1085 ociType = OciDataType.Integer;
1087 case DbType.Currency:
1088 case DbType.Decimal:
1090 oracleType = OracleType.Number;
1091 ociType = OciDataType.Number;
1094 case DbType.DateTime:
1096 oracleType = OracleType.DateTime;
1097 ociType = OciDataType.Char;
1100 oracleType = OracleType.Double;
1101 ociType = OciDataType.Float;
1104 oracleType = OracleType.Int16;
1105 ociType = OciDataType.Integer;
1108 oracleType = OracleType.Int32;
1109 ociType = OciDataType.Integer;
1112 oracleType = OracleType.Blob;
1113 ociType = OciDataType.Blob;
1116 oracleType = OracleType.Float;
1117 ociType = OciDataType.Float;
1120 oracleType = OracleType.NVarChar;
1121 ociType = OciDataType.VarChar;
1123 case DbType.StringFixedLength:
1124 oracleType = OracleType.NChar;
1125 ociType = OciDataType.Char;
1129 throw new ArgumentException (exception);
1134 private void SetOracleType (OracleType type, bool inferring)
1140 valType = typeof(System.DBNull);
1142 valType = value.GetType ();
1144 string exception = String.Format ("No mapping exists from OracleType {0} to a known DbType.", type);
1146 case OracleType.BFile:
1147 case OracleType.Blob:
1148 dbType = DbType.Binary;
1149 ociType = OciDataType.Blob;
1151 case OracleType.LongRaw:
1152 case OracleType.Raw:
1153 if (valType.FullName == "System.Guid")
1154 dbType = DbType.Guid;
1156 dbType = DbType.Binary;
1157 ociType = OciDataType.Raw;
1159 case OracleType.Byte:
1160 dbType = DbType.Byte;
1161 ociType = OciDataType.Number;
1163 case OracleType.Char:
1164 dbType = DbType.AnsiString;
1165 ociType = OciDataType.Char;
1167 case OracleType.Clob:
1168 dbType = DbType.AnsiString;
1169 ociType = OciDataType.Clob;
1171 case OracleType.LongVarChar:
1172 case OracleType.RowId:
1173 case OracleType.VarChar:
1174 dbType = DbType.AnsiString;
1175 ociType = OciDataType.VarChar;
1177 case OracleType.Cursor: // REF CURSOR
1178 ociType = OciDataType.RSet;
1179 dbType = DbType.Object;
1181 case OracleType.IntervalDayToSecond:
1182 dbType = DbType.AnsiStringFixedLength;
1183 ociType = OciDataType.Char;
1185 case OracleType.Timestamp:
1186 case OracleType.TimestampLocal:
1187 case OracleType.TimestampWithTZ:
1188 dbType = DbType.DateTime;
1189 ociType = OciDataType.TimeStamp;
1191 case OracleType.DateTime:
1192 dbType = DbType.DateTime;
1193 ociType = OciDataType.Date;
1195 case OracleType.Double:
1196 dbType = DbType.Double;
1197 ociType = OciDataType.Number;
1199 case OracleType.Float:
1200 dbType = DbType.Single;
1201 ociType = OciDataType.Number;
1203 case OracleType.Int16:
1204 dbType = DbType.Int16;
1205 ociType = OciDataType.Number;
1207 case OracleType.Int32:
1208 case OracleType.IntervalYearToMonth:
1209 dbType = DbType.Int32;
1210 ociType = OciDataType.Number;
1212 case OracleType.NChar:
1213 dbType = DbType.StringFixedLength;
1214 ociType = OciDataType.Char;
1216 case OracleType.NClob:
1217 case OracleType.NVarChar:
1218 dbType = DbType.String;
1219 ociType = OciDataType.Char;
1221 case OracleType.Number:
1222 dbType = DbType.VarNumeric;
1223 ociType = OciDataType.Number;
1225 case OracleType.SByte:
1226 dbType = DbType.SByte;
1227 ociType = OciDataType.Number;
1229 case OracleType.UInt16:
1230 dbType = DbType.UInt16;
1231 ociType = OciDataType.Number;
1233 case OracleType.UInt32:
1234 dbType = DbType.UInt32;
1235 ociType = OciDataType.Number;
1238 throw new ArgumentException (exception);
1241 if (!oracleTypeSet || !inferring )
1246 public override void ResetDbType ()
1251 public void ResetOracleType ()
1253 oracleTypeSet = false;
1254 InferOracleType (value);
1258 public override string ToString ()
1260 return ParameterName;
1263 private void GetOutValue (OracleCommand cmd)
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)
1272 IntPtr env = IntPtr.Zero;
1273 StringBuilder ret = null;
1275 // FIXME: redo all types - see how Char, Number, and Date are done
1276 // here and in Bind()
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
1288 env = cmd.Connection.Environment;
1289 OciCalls.OCICharSetToUnicode (env, null, bytes, out rsize);
1292 ret = new StringBuilder(rsize);
1293 OciCalls.OCICharSetToUnicode (env, ret, bytes, out rsize);
1295 value = ret.ToString ();
1297 case OciDataType.Long:
1298 case OciDataType.LongVarChar:
1300 if (BitConverter.IsLittleEndian)
1301 longSize = BitConverter.ToInt32 (new byte [] {bytes [0], bytes [1], bytes [2], bytes [3]}, 0);
1303 longSize = BitConverter.ToInt32 (new byte [] {bytes [3], bytes [2], bytes [1], bytes [0]}, 0);
1305 ASCIIEncoding encoding = new ASCIIEncoding ();
1306 value = encoding.GetString (bytes, 4, longSize);
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);
1315 longrawSize = BitConverter.ToInt32 (new byte [] {bytes [3], bytes [2], bytes [1], bytes [0]}, 0);
1317 byte[] longraw_buffer = new byte [longrawSize];
1318 Array.ConstrainedCopy (bytes, 4, longraw_buffer, 0, longrawSize);
1319 value = longraw_buffer;
1321 case OciDataType.Raw:
1322 case OciDataType.VarRaw:
1324 if (BitConverter.IsLittleEndian)
1325 rawSize = (int) BitConverter.ToInt16 (new byte [] {bytes [0], bytes [1]}, 0);
1327 rawSize = (int) BitConverter.ToInt16 (new byte [] {bytes [1], bytes [0]}, 0);
1329 byte[] raw_buffer = new byte [rawSize];
1330 Array.ConstrainedCopy (bytes, 2, raw_buffer, 0, rawSize);
1333 case OciDataType.Integer:
1334 case OciDataType.Number:
1335 case OciDataType.Float:
1337 env = cmd.Connection.Environment;
1338 OciCalls.OCICharSetToUnicode (env, null, bytes, out rsize);
1341 ret = new StringBuilder(rsize);
1342 OciCalls.OCICharSetToUnicode (env, ret, bytes, out rsize);
1344 // if not empty, parse string as a decimal using session format
1345 if (ret.Length > 0) {
1348 value = UInt16.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1351 value = UInt32.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1354 value = Int16.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1357 value = Int32.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1360 value = Decimal.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1365 case OciDataType.TimeStamp:
1366 value = dateTimeDesc.GetDateTime (connection.Environment, dateTimeDesc.ErrorHandle);
1368 case OciDataType.Date:
1369 value = UnpackDate (bytes);
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;
1378 OracleLob lob = new OracleLob (lobLocator, ociType);
1379 lob.connection = connection;
1383 case OciDataType.RSet: // REF CURSOR
1384 OciStatementHandle cursorStatement = GetOutRefCursor (cmd);
1385 value = new OracleDataReader (cursorStatement.Command, cursorStatement, true, CommandBehavior.Default);
1388 throw new NotImplementedException ("Data Type not implemented: " + ociType.ToString() + ".");
1392 internal OciStatementHandle GetOutRefCursor (OracleCommand cmd)
1394 OciStatementHandle cursorStatement = new OciStatementHandle (cmd.Connection.ServiceContext, cursor);
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;
1404 internal void Update (OracleCommand cmd)
1406 if (Direction != ParameterDirection.Input)
1412 internal void FreeHandle ()
1415 case OciDataType.Clob:
1416 case OciDataType.Blob:
1419 case OciDataType.TimeStamp:
1422 Marshal.FreeHGlobal (bindOutValue);
1426 bindOutValue = IntPtr.Zero;
1427 bindValue = IntPtr.Zero;
1433 // copied from OciDefineHandle
1434 [MonoTODO ("Be able to handle negative dates... i.e. BCE.")]
1435 private DateTime UnpackDate (byte[] bytes)
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];
1446 return new DateTime ((century - 100) * 100 + (year - 100),
1455 private byte[] PackDate (DateTime dateValue)
1457 byte[] buffer = new byte[7];
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);
1470 public void Dispose ()
1475 void Dispose (bool disposing)
1478 GC.SuppressFinalize(this);
1480 if (indicator != IntPtr.Zero) {
1481 Marshal.FreeHGlobal (indicator);
1482 indicator = IntPtr.Zero;
1486 #endregion // Methods
1488 internal sealed class OracleParameterConverter : ExpandableObjectConverter
1490 public OracleParameterConverter ()
1495 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
1497 throw new NotImplementedException ();
1501 public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
1503 throw new NotImplementedException ();