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
50 OracleType oracleType = OracleType.VarChar;
53 ParameterDirection direction = ParameterDirection.Input;
59 bool sourceColumnNullMapping;
61 DataRowVersion srcVersion;
62 DbType dbType = DbType.AnsiString;
66 object value = DBNull.Value;
67 OciLobLocator lobLocator; // only if Blob or Clob
68 IntPtr bindOutValue = IntPtr.Zero;
69 OciDateTimeDescriptor dateTimeDesc;
70 IntPtr cursor = IntPtr.Zero;
72 OracleParameterCollection container;
73 OciBindHandle bindHandle;
74 OracleConnection connection;
76 IntPtr bindValue = IntPtr.Zero;
88 // constructor for cloning the object
89 private OracleParameter (OracleParameter value)
91 this.name = value.name;
92 this.oracleType = value.oracleType;
93 this.ociType = value.ociType;
94 this.size = value.size;
95 this.direction = value.direction;
96 this.isNullable = value.isNullable;
97 this.precision = value.precision;
98 this.scale = value.scale;
99 this.srcColumn = value.srcColumn;
100 this.srcVersion = value.srcVersion;
101 this.dbType = value.dbType;
102 this.offset = value.offset;
103 this.sizeSet = value.sizeSet;
104 this.value = value.value;
105 this.lobLocator = value.lobLocator;
106 this.oracleTypeSet = value.oracleTypeSet;
109 public OracleParameter ()
111 this.name = String.Empty;
112 this.oracleType = OracleType.VarChar;
114 this.direction = ParameterDirection.Input;
115 this.isNullable = false;
118 this.srcColumn = String.Empty;
119 this.srcVersion = DataRowVersion.Current;
121 this.oracleTypeSet = false;
124 public OracleParameter (string name, object value)
129 srcColumn = string.Empty;
130 SourceVersion = DataRowVersion.Current;
131 InferOracleType (value);
133 // Find the OciType before inferring for the size
134 if (value != null && value != DBNull.Value) {
136 this.size = InferSize ();
141 public OracleParameter (string name, OracleType oracleType)
142 : this (name, oracleType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
146 public OracleParameter (string name, OracleType oracleType, int size)
147 : this (name, oracleType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
151 public OracleParameter (string name, OracleType oracleType, int size, string srcColumn)
152 : this (name, oracleType, size, ParameterDirection.Input, false, 0, 0, srcColumn, DataRowVersion.Current, null)
157 public OracleParameter (string name, OracleType oracleType, int size, ParameterDirection direction, string sourceColumn, DataRowVersion sourceVersion, bool sourceColumnNullMapping, object value)
161 throw new ArgumentException("Size must be not be negative.");
165 Direction = direction;
167 // set sizeSet to true iff value is not-null or non-zero size value
168 if (((value != null && value != DBNull.Value) || Direction == ParameterDirection.Output) &&
172 SourceColumnNullMapping = sourceColumnNullMapping;
173 OracleType = oracleType;
174 SourceColumn = sourceColumn;
175 SourceVersion = sourceVersion;
179 public OracleParameter (string name, OracleType oracleType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string srcColumn, DataRowVersion srcVersion, object value)
183 throw new ArgumentException("Size must be not be negative.");
188 Direction = direction;
190 // set sizeSet to true iff value is not-null or non-zero size value
191 if (((value != null && value != DBNull.Value) || Direction == ParameterDirection.Output) &&
195 this.isNullable = isNullable;
196 this.precision = precision;
199 OracleType = oracleType;
200 SourceColumn = srcColumn;
201 SourceVersion = srcVersion;
204 #endregion // Constructors
208 internal OracleParameterCollection Container {
209 get { return container; }
210 set { container = value; }
215 [RefreshProperties (RefreshProperties.All)]
216 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
223 get { return dbType; }
224 set { SetDbType (value); }
228 [DefaultValue (ParameterDirection.Input)]
230 [RefreshProperties (RefreshProperties.All)]
235 ParameterDirection Direction {
236 get { return direction; }
239 if (this.size > 0 && direction == ParameterDirection.Output)
247 [DefaultValue (false)]
248 [EditorBrowsable (EditorBrowsableState.Never)]
255 get { return isNullable; }
256 set { isNullable = value; }
260 [EditorBrowsable (EditorBrowsableState.Advanced)]
266 get { return offset; }
267 set { offset = value; }
270 [DefaultValue (OracleType.VarChar)]
271 [RefreshProperties (RefreshProperties.All)]
273 [DbProviderSpecificTypeProperty (true)]
275 public OracleType OracleType {
276 get { return oracleType; }
278 oracleTypeSet = true;
279 SetOracleType (value, false);
290 string ParameterName {
296 set { name = value; }
301 [EditorBrowsable (EditorBrowsableState.Never)]
302 [Obsolete("Set the precision of a decimal use the Math classes.")]
306 public byte Precision {
307 get { return precision; }
308 set { /* NO EFFECT*/ }
313 [EditorBrowsable (EditorBrowsableState.Never)]
314 [Obsolete("Set the precision of a decimal use the Math classes.")]
319 get { return scale; }
320 set { /* NO EFFECT*/ }
335 sizeManuallySet = true;
346 string SourceColumn {
347 get { return srcColumn; }
348 set { srcColumn = value; }
353 public override bool SourceColumnNullMapping {
354 get { return sourceColumnNullMapping; }
355 set { sourceColumnNullMapping = value; }
360 [DefaultValue ("Current")]
366 DataRowVersion SourceVersion {
367 get { return srcVersion; }
368 set { srcVersion = value; }
372 [DefaultValue (null)]
374 [RefreshProperties (RefreshProperties.All)]
375 [TypeConverter (typeof(StringConverter))]
381 get { return this.value; }
385 InferOracleType (value);
387 if (value != null && value != DBNull.Value) {
388 this.size = InferSize ();
395 #endregion // Properties
399 private void AssertSizeIsSet ()
402 case OciDataType.VarChar2:
403 case OciDataType.String:
404 case OciDataType.VarChar:
405 case OciDataType.Char:
406 case OciDataType.CharZ:
407 case OciDataType.OciString:
409 throw new Exception ("Size must be set.");
416 internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos)
420 if (bindHandle == null)
421 bindHandle = new OciBindHandle ((OciHandle) statement);
423 IntPtr tmpHandle = bindHandle.Handle;
425 if (Direction != ParameterDirection.Input)
443 if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) {
446 else if (v is DBNull)
449 INullable mynullable = v as INullable;
450 if (mynullable != null)
451 isnull = mynullable.IsNull;
455 if (isnull == true && direction == ParameterDirection.Input) {
457 bindType = OciDataType.VarChar2;
461 case OciDataType.VarChar2:
462 case OciDataType.String:
463 case OciDataType.VarChar:
464 case OciDataType.Char:
465 case OciDataType.CharZ:
466 case OciDataType.OciString:
467 bindType = OciDataType.String;
470 // convert value from managed type to type to marshal
471 if (direction == ParameterDirection.Input ||
472 direction == ParameterDirection.InputOutput) {
474 svalue = v.ToString ();
476 if (direction == ParameterDirection.Input && size > 0 && svalue.Length > size)
477 svalue = svalue.Substring(0, size);
479 svalue = svalue.ToString () + '\0';
481 // convert managed type to memory allocated earlier
482 // in this case using OCIUnicodeToCharSet
484 // Get size of buffer
485 status = OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
487 if (direction == ParameterDirection.Input)
490 // this cannot be rsize because you need room for the output after the execute
491 bindSize = Encoding.UTF8.GetMaxByteCount (Size + 1);
494 // allocate memory based on bind size
495 bytes = new byte [bindSize];
498 status = OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
500 // for Output and ReturnValue parameters, get size in bytes
501 bindSize = Encoding.UTF8.GetMaxByteCount (size + 1);
502 // allocate memory for oracle to place the results for the Return or Output param
503 bytes = new byte [bindSize];
506 case OciDataType.Date:
507 bindType = OciDataType.Date;
509 // convert value from managed type to type to marshal
510 if (direction == ParameterDirection.Input ||
511 direction == ParameterDirection.InputOutput) {
514 bytes = new byte [7];
517 dt = DateTime.MinValue;
520 dt = DateTime.Parse (sDate);
522 else if (v is DateTime)
524 else if (v is OracleString) {
525 sDate = v.ToString ();
526 dt = DateTime.Parse (sDate);
528 else if (v is OracleDateTime) {
529 OracleDateTime odt = (OracleDateTime) v;
530 dt = (DateTime) odt.Value;
533 throw new NotImplementedException ("For OracleType.DateTime, data type not implemented: " + v.GetType().ToString() + ".");
535 // for Input and InputOuput, create byte array and pack DateTime into it
536 bytes = PackDate (dt);
539 // allocate 7-byte array for Output and ReturnValue to put date
540 bytes = new byte [7];
543 case OciDataType.TimeStamp:
544 dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
545 if (dateTimeDesc == null) {
546 OciErrorInfo info = connection.ErrorHandle.HandleError ();
547 throw new OracleException (info.ErrorCode, info.ErrorMessage);
549 dateTimeDesc.ErrorHandle = connection.ErrorHandle;
551 bindType = OciDataType.TimeStamp;
552 bindOutValue = dateTimeDesc.Handle;
553 bindValue = dateTimeDesc.Handle;
555 if (direction == ParameterDirection.Input ||
556 direction == ParameterDirection.InputOutput) {
558 dt = DateTime.MinValue;
562 else if (v is String) {
564 dt = DateTime.Parse (sDate);
566 else if (v is DateTime)
568 else if (v is OracleString) {
570 dt = DateTime.Parse (sDate);
572 else if (v is OracleDateTime) {
573 OracleDateTime odt = (OracleDateTime) v;
574 dt = (DateTime) odt.Value;
577 throw new NotImplementedException ("For OracleType.Timestamp, data type not implemented: " + v.GetType().ToString()); // ?
579 short year = (short) dt.Year;
580 byte month = (byte) dt.Month;
581 byte day = (byte) dt.Day;
582 byte hour = (byte) dt.Hour;
583 byte min = (byte) dt.Minute;
584 byte sec = (byte) dt.Second;
585 uint fsec = (uint) dt.Millisecond;
586 string timezone = "";
587 dateTimeDesc.SetDateTime (connection.Session,
588 connection.ErrorHandle,
589 year, month, day, hour, min, sec, fsec,
593 case OciDataType.Integer:
594 case OciDataType.Float:
595 case OciDataType.Number:
596 bindType = OciDataType.String;
599 // convert value from managed type to type to marshal
600 if (direction == ParameterDirection.Input ||
601 direction == ParameterDirection.InputOutput) {
604 if(v is IFormattable)
605 svalue = ((IFormattable)v).ToString (null, con.SessionFormatProvider);
606 else if (v is OracleNumber)
607 svalue = ((OracleNumber)v).ToString(con.SessionFormatProvider);
609 svalue = v.ToString();
611 svalue = svalue + "\0";
614 // Get size of buffer
615 OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
619 if (direction == ParameterDirection.Input)
622 bindSize = 30; // need room for output possibly being bigger than the input
624 bytes = new byte [bindSize];
625 OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
627 // Output and ReturnValue parameters allocate memory
629 bytes = new byte [bindSize];
632 case OciDataType.Long:
633 case OciDataType.LongVarChar:
634 bindType = OciDataType.LongVarChar;
636 // FIXME: use piecewise fetching for Long, Clob, Blob, and Long Raw
637 // See http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci05bnd.htm#sthref724
639 bindSize = Size + 5; // 4 bytes prepended for length, bytes, 1 byte NUL character
643 // convert value from managed type to type to marshal
644 if (direction == ParameterDirection.Input ||
645 direction == ParameterDirection.InputOutput) {
647 svalue = v.ToString () + '\0';
650 bytes = new byte [bindSize];
652 ASCIIEncoding enc = new ASCIIEncoding ();
654 if (direction == ParameterDirection.Input ||
655 direction == ParameterDirection.InputOutput) {
656 if (svalue.Length > 0) {
657 byteCount = enc.GetBytes (svalue, 4, svalue.Length, bytes, 0);
658 // LONG VARCHAR prepends a 4-byte length
660 byteArrayLen = BitConverter.GetBytes ((uint) byteCount);
661 bytes[0] = byteArrayLen[0];
662 bytes[1] = byteArrayLen[1];
663 bytes[2] = byteArrayLen[2];
664 bytes[3] = byteArrayLen[3];
669 case OciDataType.Clob:
670 if (direction == ParameterDirection.Input) {
671 svalue = v.ToString();
674 // Get size of buffer
675 OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
678 bytes = new byte[rsize];
679 OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
681 bindType = OciDataType.Long;
682 bindSize = bytes.Length;
684 else if (direction == ParameterDirection.InputOutput) {
685 // not the exact error that .net 2.0 throws, but this is better
686 throw new NotImplementedException ("Parameters of OracleType.Clob with direction of InputOutput are not supported.");
689 // Output and Return parameters
691 lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
692 if (lobLocator == null) {
693 OciErrorInfo info = connection.ErrorHandle.HandleError ();
694 throw new OracleException (info.ErrorCode, info.ErrorMessage);
696 bindOutValue = lobLocator.Handle;
697 bindValue = lobLocator.Handle;
698 lobLocator.ErrorHandle = connection.ErrorHandle;
699 lobLocator.Service = statement.Service;
700 lobLocator.Environment = connection.Environment;
704 case OciDataType.Blob:
705 if (direction == ParameterDirection.Input) {
708 bindType = OciDataType.LongRaw;
709 bindSize = bytes.Length;
711 else if (v is OracleLob) {
712 OracleLob lob = (OracleLob) v;
713 if (lob.LobType == OracleType.Blob) {
714 lobLocator = lob.Locator;
715 bindOutValue = lobLocator.Handle;
716 bindValue = lobLocator.Handle;
717 lobLocator.ErrorHandle = connection.ErrorHandle;
718 lobLocator.Service = connection.ServiceContext;
722 throw new NotImplementedException("For OracleType.Blob, data type OracleLob of LobType Clob/NClob is not implemented.");
725 throw new NotImplementedException ("For OracleType.Blob, data type not implemented: " + v.GetType().ToString()); // ?
727 else if (direction == ParameterDirection.InputOutput) {
728 // not the exact error that .net 2.0 throws, but this is better
729 throw new NotImplementedException ("Parameters of OracleType.Blob with direction of InputOutput are not supported.");
733 if (value != null && value is OracleLob) {
734 OracleLob blob = (OracleLob) value;
735 if (blob.LobType == OracleType.Blob)
736 if (value != OracleLob.Null) {
737 lobLocator = blob.Locator;
738 byte[] bs = (byte[]) blob.Value;
739 bindSize = bs.Length;
742 if (lobLocator == null) {
743 lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
744 if (lobLocator == null) {
745 OciErrorInfo info = connection.ErrorHandle.HandleError ();
746 throw new OracleException (info.ErrorCode, info.ErrorMessage);
749 bindOutValue = lobLocator.Handle;
750 bindValue = lobLocator.Handle;
751 lobLocator.ErrorHandle = connection.ErrorHandle;
752 lobLocator.Service = connection.ServiceContext;
753 lobLocator.Environment = connection.Environment;
757 case OciDataType.Raw:
758 case OciDataType.VarRaw:
759 bindType = OciDataType.VarRaw;
760 bindSize = Size + 2; // include 2 bytes prepended to hold the length
762 bytes = new byte [bindSize];
763 if (direction == ParameterDirection.Input ||
764 direction == ParameterDirection.InputOutput) {
767 if (dbType == DbType.Guid)
768 val = ((Guid)v).ToByteArray();
771 if (val.Length > 0) {
772 byteCount = val.Length;
773 // LONG VARRAW prepends a 4-byte length
775 byteArrayLen = BitConverter.GetBytes ((ushort) byteCount);
776 bytes[0] = byteArrayLen[0];
777 bytes[1] = byteArrayLen[1];
778 Array.ConstrainedCopy (val, 0, bytes, 2, byteCount);
783 case OciDataType.LongRaw:
784 case OciDataType.LongVarRaw:
785 bindType = OciDataType.LongVarRaw;
786 bindSize = Size + 4; // include 4 bytes prepended to hold the length
788 bytes = new byte [bindSize];
789 if (direction == ParameterDirection.Input ||
790 direction == ParameterDirection.InputOutput) {
792 byte[] val = v as byte[];
793 if (val.Length > 0) {
794 byteCount = val.Length;
795 // LONG VARRAW prepends a 4-byte length
797 byteArrayLen = BitConverter.GetBytes ((uint) byteCount);
798 bytes[0] = byteArrayLen[0];
799 bytes[1] = byteArrayLen[1];
800 bytes[2] = byteArrayLen[2];
801 bytes[3] = byteArrayLen[3];
802 Array.ConstrainedCopy (val, 0, bytes, 4, byteCount);
807 case OciDataType.RowIdDescriptor:
808 if (direction == ParameterDirection.Output ||
809 direction == ParameterDirection.InputOutput ||
810 direction == ParameterDirection.ReturnValue) {
813 bindType = OciDataType.Char;
815 bindOutValue = OciCalls.AllocateClear (bindSize);
816 bindValue = bindOutValue;
818 throw new NotImplementedException("data type RowIdDescriptor as Intput parameters");
820 case OciDataType.RSet: // REF CURSOR
821 if (direction == ParameterDirection.Output ||
822 direction == ParameterDirection.InputOutput ||
823 direction == ParameterDirection.ReturnValue) {
825 cursor = IntPtr.Zero;
826 OciCalls.OCIHandleAlloc (connection.Environment,
828 OciHandleType.Statement,
832 bindType = OciDataType.RSet;
834 throw new NotImplementedException ("data type Ref Cursor not implemented for Input parameters");
837 throw new NotImplementedException ("Data Type not implemented: " + ociType.ToString() + ".");
841 // Now, call the appropriate OCI Bind function;
843 if (useRef == true) {
844 if (bindType == OciDataType.TimeStamp) {
845 bindValue = dateTimeDesc.Handle;
846 status = OciCalls.OCIBindByNameRef (statement,
848 connection.ErrorHandle,
850 ParameterName.Length,
862 status = OciCalls.OCIBindByNameRef (statement,
864 connection.ErrorHandle,
866 ParameterName.Length,
878 else if (bindType == OciDataType.RSet) {
879 status = OciCalls.OCIBindByNameRef (statement,
881 connection.ErrorHandle,
883 ParameterName.Length,
894 else if (bytes != null) {
895 status = OciCalls.OCIBindByNameBytes (statement,
897 connection.ErrorHandle,
899 ParameterName.Length,
911 status = OciCalls.OCIBindByName (statement,
913 connection.ErrorHandle,
915 ParameterName.Length, // FIXME: this should be in bytes!
926 OciErrorHandle.ThrowExceptionIfError (connection.ErrorHandle, status);
928 bindHandle.SetHandle (tmpHandle);
931 object ICloneable.Clone ()
933 return new OracleParameter(this);
936 private void InferOracleType (object value)
938 // Should we throw an exception here?
939 if (value == null || value == DBNull.Value)
942 Type type = value.GetType ();
943 string exception = String.Format ("The parameter data type of {0} is invalid.", type.FullName);
944 switch (type.FullName) {
946 SetOracleType (OracleType.Number, true);
948 case "System.Boolean":
950 SetOracleType (OracleType.Byte, true);
952 case "System.String":
953 case "System.Data.OracleClient.OracleString":
954 SetOracleType (OracleType.VarChar, true);
956 case "System.Data.OracleClient.OracleDateTime":
957 case "System.DateTime":
958 SetOracleType (OracleType.DateTime, true);
960 case "System.Decimal":
961 case "System.Data.OracleClient.OracleNumber":
962 SetOracleType (OracleType.Number, true);
964 case "System.Double":
965 SetOracleType (OracleType.Double, true);
967 case "System.Byte[]":
969 SetOracleType (OracleType.Raw, true);
972 SetOracleType (OracleType.Int32, true);
974 case "System.Single":
975 SetOracleType (OracleType.Float, true);
978 SetOracleType (OracleType.Int16, true);
980 case "System.DBNull":
981 break; //unable to guess type
982 case "System.Data.OracleClient.OracleLob":
983 SetOracleType (((OracleLob) value).LobType, true);
986 throw new ArgumentException (exception);
990 private int InferSize ()
995 case OciDataType.VarChar2:
996 case OciDataType.String:
997 case OciDataType.VarChar:
998 case OciDataType.Char:
999 case OciDataType.CharZ:
1000 case OciDataType.OciString:
1001 case OciDataType.Long:
1002 case OciDataType.LongVarChar:
1003 if (sizeManuallySet == true)
1005 if (value == null || value == DBNull.Value)
1008 newSize = value.ToString ().Length;
1010 case OciDataType.RowIdDescriptor:
1013 case OciDataType.Integer:
1014 case OciDataType.Number:
1015 case OciDataType.Float:
1018 case OciDataType.Date:
1021 case OciDataType.TimeStamp:
1024 case OciDataType.Blob:
1025 case OciDataType.Clob:
1026 case OciDataType.RSet: // REF CURSOR
1029 case OciDataType.Raw:
1030 if (dbType == DbType.Guid)
1031 newSize = ((Guid)value).ToByteArray().Length;
1033 newSize = (value as byte[]).Length;
1036 if (value == null || value == DBNull.Value)
1039 newSize = value.ToString ().Length;
1048 private void SetDbType (DbType type)
1050 string exception = String.Format ("No mapping exists from DbType {0} to a known OracleType.", type);
1052 case DbType.AnsiString:
1053 oracleType = OracleType.VarChar;
1054 ociType = OciDataType.VarChar;
1056 case DbType.AnsiStringFixedLength:
1057 oracleType = OracleType.Char;
1058 ociType = OciDataType.Char;
1062 oracleType = OracleType.Raw;
1063 ociType = OciDataType.Raw;
1065 case DbType.Boolean:
1067 oracleType = OracleType.Byte;
1068 ociType = OciDataType.Integer;
1070 case DbType.Currency:
1071 case DbType.Decimal:
1073 oracleType = OracleType.Number;
1074 ociType = OciDataType.Number;
1077 case DbType.DateTime:
1079 oracleType = OracleType.DateTime;
1080 ociType = OciDataType.Char;
1083 oracleType = OracleType.Double;
1084 ociType = OciDataType.Float;
1087 oracleType = OracleType.Int16;
1088 ociType = OciDataType.Integer;
1091 oracleType = OracleType.Int32;
1092 ociType = OciDataType.Integer;
1095 oracleType = OracleType.Blob;
1096 ociType = OciDataType.Blob;
1099 oracleType = OracleType.Float;
1100 ociType = OciDataType.Float;
1103 oracleType = OracleType.NVarChar;
1104 ociType = OciDataType.VarChar;
1106 case DbType.StringFixedLength:
1107 oracleType = OracleType.NChar;
1108 ociType = OciDataType.Char;
1112 throw new ArgumentException (exception);
1117 private void SetOracleType (OracleType type, bool inferring)
1120 Type valType = value.GetType ();
1121 string exception = String.Format ("No mapping exists from OracleType {0} to a known DbType.", type);
1123 case OracleType.BFile:
1124 case OracleType.Blob:
1125 dbType = DbType.Binary;
1126 ociType = OciDataType.Blob;
1128 case OracleType.LongRaw:
1129 case OracleType.Raw:
1130 if (valType.FullName == "System.Guid")
1131 dbType = DbType.Guid;
1133 dbType = DbType.Binary;
1134 ociType = OciDataType.Raw;
1136 case OracleType.Byte:
1137 dbType = DbType.Byte;
1138 ociType = OciDataType.Number;
1140 case OracleType.Char:
1141 dbType = DbType.AnsiString;
1142 ociType = OciDataType.Char;
1144 case OracleType.Clob:
1145 dbType = DbType.AnsiString;
1146 ociType = OciDataType.Clob;
1148 case OracleType.LongVarChar:
1149 case OracleType.RowId:
1150 case OracleType.VarChar:
1151 dbType = DbType.AnsiString;
1152 ociType = OciDataType.VarChar;
1154 case OracleType.Cursor: // REF CURSOR
1155 ociType = OciDataType.RSet;
1156 dbType = DbType.Object;
1158 case OracleType.IntervalDayToSecond:
1159 dbType = DbType.AnsiStringFixedLength;
1160 ociType = OciDataType.Char;
1162 case OracleType.Timestamp:
1163 case OracleType.TimestampLocal:
1164 case OracleType.TimestampWithTZ:
1165 dbType = DbType.DateTime;
1166 ociType = OciDataType.TimeStamp;
1168 case OracleType.DateTime:
1169 dbType = DbType.DateTime;
1170 ociType = OciDataType.Date;
1172 case OracleType.Double:
1173 dbType = DbType.Double;
1174 ociType = OciDataType.Number;
1176 case OracleType.Float:
1177 dbType = DbType.Single;
1178 ociType = OciDataType.Number;
1180 case OracleType.Int16:
1181 dbType = DbType.Int16;
1182 ociType = OciDataType.Number;
1184 case OracleType.Int32:
1185 case OracleType.IntervalYearToMonth:
1186 dbType = DbType.Int32;
1187 ociType = OciDataType.Number;
1189 case OracleType.NChar:
1190 dbType = DbType.StringFixedLength;
1191 ociType = OciDataType.Char;
1193 case OracleType.NClob:
1194 case OracleType.NVarChar:
1195 dbType = DbType.String;
1196 ociType = OciDataType.Char;
1198 case OracleType.Number:
1199 dbType = DbType.VarNumeric;
1200 ociType = OciDataType.Number;
1202 case OracleType.SByte:
1203 dbType = DbType.SByte;
1204 ociType = OciDataType.Number;
1206 case OracleType.UInt16:
1207 dbType = DbType.UInt16;
1208 ociType = OciDataType.Number;
1210 case OracleType.UInt32:
1211 dbType = DbType.UInt32;
1212 ociType = OciDataType.Number;
1215 throw new ArgumentException (exception);
1218 if (!oracleTypeSet || !inferring )
1223 public override void ResetDbType ()
1228 public void ResetOracleType ()
1230 oracleTypeSet = false;
1231 InferOracleType (value);
1235 public override string ToString ()
1237 return ParameterName;
1240 private void GetOutValue (OracleCommand cmd)
1242 // used to update the parameter value
1243 // for Output, the output of InputOutput, and Return parameters
1244 value = DBNull.Value;
1245 if (indicator == -1)
1249 IntPtr env = IntPtr.Zero;
1250 StringBuilder ret = null;
1252 // FIXME: redo all types - see how Char, Number, and Date are done
1253 // here and in Bind()
1256 case OciDataType.VarChar2:
1257 case OciDataType.String:
1258 case OciDataType.VarChar:
1259 case OciDataType.Char:
1260 case OciDataType.CharZ:
1261 case OciDataType.OciString:
1262 case OciDataType.RowIdDescriptor:
1263 // Get length of returned string
1265 env = cmd.Connection.Environment;
1266 OciCalls.OCICharSetToUnicode (env, null, bytes, out rsize);
1269 ret = new StringBuilder(rsize);
1270 OciCalls.OCICharSetToUnicode (env, ret, bytes, out rsize);
1272 value = ret.ToString ();
1274 case OciDataType.Long:
1275 case OciDataType.LongVarChar:
1277 if (BitConverter.IsLittleEndian)
1278 longSize = BitConverter.ToInt32 (new byte [] {bytes [0], bytes [1], bytes [2], bytes [3]}, 0);
1280 longSize = BitConverter.ToInt32 (new byte [] {bytes [3], bytes [2], bytes [1], bytes [0]}, 0);
1282 ASCIIEncoding encoding = new ASCIIEncoding ();
1283 value = encoding.GetString (bytes, 4, longSize);
1286 case OciDataType.LongRaw:
1287 case OciDataType.LongVarRaw:
1288 int longrawSize = 0;
1289 if (BitConverter.IsLittleEndian)
1290 longrawSize = BitConverter.ToInt32 (new byte [] {bytes [0], bytes [1], bytes [2], bytes [3]}, 0);
1292 longrawSize = BitConverter.ToInt32 (new byte [] {bytes [3], bytes [2], bytes [1], bytes [0]}, 0);
1294 byte[] longraw_buffer = new byte [longrawSize];
1295 Array.ConstrainedCopy (bytes, 4, longraw_buffer, 0, longrawSize);
1296 value = longraw_buffer;
1298 case OciDataType.Raw:
1299 case OciDataType.VarRaw:
1301 if (BitConverter.IsLittleEndian)
1302 rawSize = (int) BitConverter.ToInt16 (new byte [] {bytes [0], bytes [1]}, 0);
1304 rawSize = (int) BitConverter.ToInt16 (new byte [] {bytes [1], bytes [0]}, 0);
1306 byte[] raw_buffer = new byte [rawSize];
1307 Array.ConstrainedCopy (bytes, 2, raw_buffer, 0, rawSize);
1310 case OciDataType.Integer:
1311 case OciDataType.Number:
1312 case OciDataType.Float:
1314 env = cmd.Connection.Environment;
1315 OciCalls.OCICharSetToUnicode (env, null, bytes, out rsize);
1318 ret = new StringBuilder(rsize);
1319 OciCalls.OCICharSetToUnicode (env, ret, bytes, out rsize);
1321 // if not empty, parse string as a decimal using session format
1322 if (ret.Length > 0) {
1325 value = UInt16.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1328 value = UInt32.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1331 value = Int16.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1334 value = Int32.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1337 value = Decimal.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1342 case OciDataType.TimeStamp:
1343 value = dateTimeDesc.GetDateTime (connection.Environment, dateTimeDesc.ErrorHandle);
1345 case OciDataType.Date:
1346 value = UnpackDate (bytes);
1348 case OciDataType.Blob:
1349 case OciDataType.Clob:
1350 if (value != null && value is OracleLob && value != OracleLob.Null) {
1351 OracleLob lob2 = (OracleLob) value;
1352 lob2.connection = connection;
1355 OracleLob lob = new OracleLob (lobLocator, ociType);
1356 lob.connection = connection;
1360 case OciDataType.RSet: // REF CURSOR
1361 OciStatementHandle cursorStatement = GetOutRefCursor (cmd);
1362 value = new OracleDataReader (cursorStatement.Command, cursorStatement, true, CommandBehavior.Default);
1365 throw new NotImplementedException ("Data Type not implemented: " + ociType.ToString() + ".");
1369 internal OciStatementHandle GetOutRefCursor (OracleCommand cmd)
1371 OciStatementHandle cursorStatement = new OciStatementHandle (cmd.Connection.ServiceContext, cursor);
1373 cursorStatement.ErrorHandle = cmd.ErrorHandle;
1374 cursorStatement.Command = cmd;
1375 cursorStatement.SetupRefCursorResult (cmd.Connection);
1376 cursorStatement.Service = cmd.Connection.ServiceContext;
1377 cursor = IntPtr.Zero;
1378 return cursorStatement;
1381 internal void Update (OracleCommand cmd)
1383 if (Direction != ParameterDirection.Input)
1389 internal void FreeHandle ()
1392 case OciDataType.Clob:
1393 case OciDataType.Blob:
1396 case OciDataType.TimeStamp:
1399 Marshal.FreeHGlobal (bindOutValue);
1403 bindOutValue = IntPtr.Zero;
1404 bindValue = IntPtr.Zero;
1410 // copied from OciDefineHandle
1411 [MonoTODO ("Be able to handle negative dates... i.e. BCE.")]
1412 private DateTime UnpackDate (byte[] bytes)
1414 byte century = bytes [0];
1415 byte year = bytes [1];
1416 byte month = bytes [2];
1417 byte day = bytes [3];
1418 byte hour = bytes [4];
1419 byte minute = bytes [5];
1420 byte second = bytes [6];
1423 return new DateTime ((century - 100) * 100 + (year - 100),
1432 private byte[] PackDate (DateTime dateValue)
1434 byte[] buffer = new byte[7];
1436 buffer[0] = (byte)((dateValue.Year / 100) + 100); //century
1437 buffer[1] = (byte)((dateValue.Year % 100) + 100); // Year
1438 buffer[2] = (byte)dateValue.Month;
1439 buffer[3] = (byte)dateValue.Day;
1440 buffer[4] = (byte)(dateValue.Hour+1);
1441 buffer[5] = (byte)(dateValue.Minute+1);
1442 buffer[6] = (byte)(dateValue.Second+1);
1447 #endregion // Methods
1449 internal sealed class OracleParameterConverter : ExpandableObjectConverter
1451 public OracleParameterConverter ()
1456 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
1458 throw new NotImplementedException ();
1462 public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
1464 throw new NotImplementedException ();