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) {
824 if (cursor != IntPtr.Zero) {
825 OciCalls.OCIHandleFree (cursor,
826 OciHandleType.Statement);
827 cursor = IntPtr.Zero;
829 OciCalls.OCIHandleAlloc (connection.Environment,
831 OciHandleType.Statement,
835 bindType = OciDataType.RSet;
837 throw new NotImplementedException ("data type Ref Cursor not implemented for Input parameters");
840 throw new NotImplementedException ("Data Type not implemented: " + ociType.ToString() + ".");
844 // Now, call the appropriate OCI Bind function;
846 if (useRef == true) {
847 if (bindType == OciDataType.TimeStamp) {
848 bindValue = dateTimeDesc.Handle;
849 status = OciCalls.OCIBindByNameRef (statement,
851 connection.ErrorHandle,
853 ParameterName.Length,
865 status = OciCalls.OCIBindByNameRef (statement,
867 connection.ErrorHandle,
869 ParameterName.Length,
881 else if (bindType == OciDataType.RSet) {
882 status = OciCalls.OCIBindByNameRef (statement,
884 connection.ErrorHandle,
886 ParameterName.Length,
897 else if (bytes != null) {
898 status = OciCalls.OCIBindByNameBytes (statement,
900 connection.ErrorHandle,
902 ParameterName.Length,
914 status = OciCalls.OCIBindByName (statement,
916 connection.ErrorHandle,
918 ParameterName.Length, // FIXME: this should be in bytes!
929 OciErrorHandle.ThrowExceptionIfError (connection.ErrorHandle, status);
931 bindHandle.SetHandle (tmpHandle);
934 object ICloneable.Clone ()
936 return new OracleParameter(this);
939 private void InferOracleType (object value)
941 // Should we throw an exception here?
942 if (value == null || value == DBNull.Value)
945 Type type = value.GetType ();
946 string exception = String.Format ("The parameter data type of {0} is invalid.", type.FullName);
947 switch (type.FullName) {
949 SetOracleType (OracleType.Number, true);
951 case "System.Boolean":
953 SetOracleType (OracleType.Byte, true);
955 case "System.String":
956 case "System.Data.OracleClient.OracleString":
957 SetOracleType (OracleType.VarChar, true);
959 case "System.Data.OracleClient.OracleDateTime":
960 case "System.DateTime":
961 SetOracleType (OracleType.DateTime, true);
963 case "System.Decimal":
964 case "System.Data.OracleClient.OracleNumber":
965 SetOracleType (OracleType.Number, true);
967 case "System.Double":
968 SetOracleType (OracleType.Double, true);
970 case "System.Byte[]":
972 SetOracleType (OracleType.Raw, true);
975 SetOracleType (OracleType.Int32, true);
977 case "System.Single":
978 SetOracleType (OracleType.Float, true);
981 SetOracleType (OracleType.Int16, true);
983 case "System.DBNull":
984 break; //unable to guess type
985 case "System.Data.OracleClient.OracleLob":
986 SetOracleType (((OracleLob) value).LobType, true);
989 throw new ArgumentException (exception);
993 private int InferSize ()
998 case OciDataType.VarChar2:
999 case OciDataType.String:
1000 case OciDataType.VarChar:
1001 case OciDataType.Char:
1002 case OciDataType.CharZ:
1003 case OciDataType.OciString:
1004 case OciDataType.Long:
1005 case OciDataType.LongVarChar:
1006 if (sizeManuallySet == true)
1008 if (value == null || value == DBNull.Value)
1011 newSize = value.ToString ().Length;
1013 case OciDataType.RowIdDescriptor:
1016 case OciDataType.Integer:
1017 case OciDataType.Number:
1018 case OciDataType.Float:
1021 case OciDataType.Date:
1024 case OciDataType.TimeStamp:
1027 case OciDataType.Blob:
1028 case OciDataType.Clob:
1029 case OciDataType.RSet: // REF CURSOR
1032 case OciDataType.Raw:
1033 if (dbType == DbType.Guid)
1034 newSize = ((Guid)value).ToByteArray().Length;
1036 newSize = (value as byte[]).Length;
1039 if (value == null || value == DBNull.Value)
1042 newSize = value.ToString ().Length;
1051 private void SetDbType (DbType type)
1053 string exception = String.Format ("No mapping exists from DbType {0} to a known OracleType.", type);
1055 case DbType.AnsiString:
1056 oracleType = OracleType.VarChar;
1057 ociType = OciDataType.VarChar;
1059 case DbType.AnsiStringFixedLength:
1060 oracleType = OracleType.Char;
1061 ociType = OciDataType.Char;
1065 oracleType = OracleType.Raw;
1066 ociType = OciDataType.Raw;
1068 case DbType.Boolean:
1070 oracleType = OracleType.Byte;
1071 ociType = OciDataType.Integer;
1073 case DbType.Currency:
1074 case DbType.Decimal:
1076 oracleType = OracleType.Number;
1077 ociType = OciDataType.Number;
1080 case DbType.DateTime:
1082 oracleType = OracleType.DateTime;
1083 ociType = OciDataType.Char;
1086 oracleType = OracleType.Double;
1087 ociType = OciDataType.Float;
1090 oracleType = OracleType.Int16;
1091 ociType = OciDataType.Integer;
1094 oracleType = OracleType.Int32;
1095 ociType = OciDataType.Integer;
1098 oracleType = OracleType.Blob;
1099 ociType = OciDataType.Blob;
1102 oracleType = OracleType.Float;
1103 ociType = OciDataType.Float;
1106 oracleType = OracleType.NVarChar;
1107 ociType = OciDataType.VarChar;
1109 case DbType.StringFixedLength:
1110 oracleType = OracleType.NChar;
1111 ociType = OciDataType.Char;
1115 throw new ArgumentException (exception);
1120 private void SetOracleType (OracleType type, bool inferring)
1126 valType = typeof(System.DBNull);
1128 valType = value.GetType ();
1130 string exception = String.Format ("No mapping exists from OracleType {0} to a known DbType.", type);
1132 case OracleType.BFile:
1133 case OracleType.Blob:
1134 dbType = DbType.Binary;
1135 ociType = OciDataType.Blob;
1137 case OracleType.LongRaw:
1138 case OracleType.Raw:
1139 if (valType.FullName == "System.Guid")
1140 dbType = DbType.Guid;
1142 dbType = DbType.Binary;
1143 ociType = OciDataType.Raw;
1145 case OracleType.Byte:
1146 dbType = DbType.Byte;
1147 ociType = OciDataType.Number;
1149 case OracleType.Char:
1150 dbType = DbType.AnsiString;
1151 ociType = OciDataType.Char;
1153 case OracleType.Clob:
1154 dbType = DbType.AnsiString;
1155 ociType = OciDataType.Clob;
1157 case OracleType.LongVarChar:
1158 case OracleType.RowId:
1159 case OracleType.VarChar:
1160 dbType = DbType.AnsiString;
1161 ociType = OciDataType.VarChar;
1163 case OracleType.Cursor: // REF CURSOR
1164 ociType = OciDataType.RSet;
1165 dbType = DbType.Object;
1167 case OracleType.IntervalDayToSecond:
1168 dbType = DbType.AnsiStringFixedLength;
1169 ociType = OciDataType.Char;
1171 case OracleType.Timestamp:
1172 case OracleType.TimestampLocal:
1173 case OracleType.TimestampWithTZ:
1174 dbType = DbType.DateTime;
1175 ociType = OciDataType.TimeStamp;
1177 case OracleType.DateTime:
1178 dbType = DbType.DateTime;
1179 ociType = OciDataType.Date;
1181 case OracleType.Double:
1182 dbType = DbType.Double;
1183 ociType = OciDataType.Number;
1185 case OracleType.Float:
1186 dbType = DbType.Single;
1187 ociType = OciDataType.Number;
1189 case OracleType.Int16:
1190 dbType = DbType.Int16;
1191 ociType = OciDataType.Number;
1193 case OracleType.Int32:
1194 case OracleType.IntervalYearToMonth:
1195 dbType = DbType.Int32;
1196 ociType = OciDataType.Number;
1198 case OracleType.NChar:
1199 dbType = DbType.StringFixedLength;
1200 ociType = OciDataType.Char;
1202 case OracleType.NClob:
1203 case OracleType.NVarChar:
1204 dbType = DbType.String;
1205 ociType = OciDataType.Char;
1207 case OracleType.Number:
1208 dbType = DbType.VarNumeric;
1209 ociType = OciDataType.Number;
1211 case OracleType.SByte:
1212 dbType = DbType.SByte;
1213 ociType = OciDataType.Number;
1215 case OracleType.UInt16:
1216 dbType = DbType.UInt16;
1217 ociType = OciDataType.Number;
1219 case OracleType.UInt32:
1220 dbType = DbType.UInt32;
1221 ociType = OciDataType.Number;
1224 throw new ArgumentException (exception);
1227 if (!oracleTypeSet || !inferring )
1232 public override void ResetDbType ()
1237 public void ResetOracleType ()
1239 oracleTypeSet = false;
1240 InferOracleType (value);
1244 public override string ToString ()
1246 return ParameterName;
1249 private void GetOutValue (OracleCommand cmd)
1251 // used to update the parameter value
1252 // for Output, the output of InputOutput, and Return parameters
1253 value = DBNull.Value;
1254 if (indicator == -1)
1258 IntPtr env = IntPtr.Zero;
1259 StringBuilder ret = null;
1261 // FIXME: redo all types - see how Char, Number, and Date are done
1262 // here and in Bind()
1265 case OciDataType.VarChar2:
1266 case OciDataType.String:
1267 case OciDataType.VarChar:
1268 case OciDataType.Char:
1269 case OciDataType.CharZ:
1270 case OciDataType.OciString:
1271 case OciDataType.RowIdDescriptor:
1272 // Get length of returned string
1274 env = cmd.Connection.Environment;
1275 OciCalls.OCICharSetToUnicode (env, null, bytes, out rsize);
1278 ret = new StringBuilder(rsize);
1279 OciCalls.OCICharSetToUnicode (env, ret, bytes, out rsize);
1281 value = ret.ToString ();
1283 case OciDataType.Long:
1284 case OciDataType.LongVarChar:
1286 if (BitConverter.IsLittleEndian)
1287 longSize = BitConverter.ToInt32 (new byte [] {bytes [0], bytes [1], bytes [2], bytes [3]}, 0);
1289 longSize = BitConverter.ToInt32 (new byte [] {bytes [3], bytes [2], bytes [1], bytes [0]}, 0);
1291 ASCIIEncoding encoding = new ASCIIEncoding ();
1292 value = encoding.GetString (bytes, 4, longSize);
1295 case OciDataType.LongRaw:
1296 case OciDataType.LongVarRaw:
1297 int longrawSize = 0;
1298 if (BitConverter.IsLittleEndian)
1299 longrawSize = BitConverter.ToInt32 (new byte [] {bytes [0], bytes [1], bytes [2], bytes [3]}, 0);
1301 longrawSize = BitConverter.ToInt32 (new byte [] {bytes [3], bytes [2], bytes [1], bytes [0]}, 0);
1303 byte[] longraw_buffer = new byte [longrawSize];
1304 Array.ConstrainedCopy (bytes, 4, longraw_buffer, 0, longrawSize);
1305 value = longraw_buffer;
1307 case OciDataType.Raw:
1308 case OciDataType.VarRaw:
1310 if (BitConverter.IsLittleEndian)
1311 rawSize = (int) BitConverter.ToInt16 (new byte [] {bytes [0], bytes [1]}, 0);
1313 rawSize = (int) BitConverter.ToInt16 (new byte [] {bytes [1], bytes [0]}, 0);
1315 byte[] raw_buffer = new byte [rawSize];
1316 Array.ConstrainedCopy (bytes, 2, raw_buffer, 0, rawSize);
1319 case OciDataType.Integer:
1320 case OciDataType.Number:
1321 case OciDataType.Float:
1323 env = cmd.Connection.Environment;
1324 OciCalls.OCICharSetToUnicode (env, null, bytes, out rsize);
1327 ret = new StringBuilder(rsize);
1328 OciCalls.OCICharSetToUnicode (env, ret, bytes, out rsize);
1330 // if not empty, parse string as a decimal using session format
1331 if (ret.Length > 0) {
1334 value = UInt16.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1337 value = UInt32.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1340 value = Int16.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1343 value = Int32.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1346 value = Decimal.Parse (ret.ToString (), cmd.Connection.SessionFormatProvider);
1351 case OciDataType.TimeStamp:
1352 value = dateTimeDesc.GetDateTime (connection.Environment, dateTimeDesc.ErrorHandle);
1354 case OciDataType.Date:
1355 value = UnpackDate (bytes);
1357 case OciDataType.Blob:
1358 case OciDataType.Clob:
1359 if (value != null && value is OracleLob && value != OracleLob.Null) {
1360 OracleLob lob2 = (OracleLob) value;
1361 lob2.connection = connection;
1364 OracleLob lob = new OracleLob (lobLocator, ociType);
1365 lob.connection = connection;
1369 case OciDataType.RSet: // REF CURSOR
1370 OciStatementHandle cursorStatement = GetOutRefCursor (cmd);
1371 value = new OracleDataReader (cursorStatement.Command, cursorStatement, true, CommandBehavior.Default);
1374 throw new NotImplementedException ("Data Type not implemented: " + ociType.ToString() + ".");
1378 internal OciStatementHandle GetOutRefCursor (OracleCommand cmd)
1380 OciStatementHandle cursorStatement = new OciStatementHandle (cmd.Connection.ServiceContext, cursor);
1382 cursorStatement.ErrorHandle = cmd.ErrorHandle;
1383 cursorStatement.Command = cmd;
1384 cursorStatement.SetupRefCursorResult (cmd.Connection);
1385 cursorStatement.Service = cmd.Connection.ServiceContext;
1386 cursor = IntPtr.Zero;
1387 return cursorStatement;
1390 internal void Update (OracleCommand cmd)
1392 if (Direction != ParameterDirection.Input)
1398 internal void FreeHandle ()
1401 case OciDataType.Clob:
1402 case OciDataType.Blob:
1405 case OciDataType.TimeStamp:
1408 Marshal.FreeHGlobal (bindOutValue);
1412 bindOutValue = IntPtr.Zero;
1413 bindValue = IntPtr.Zero;
1419 // copied from OciDefineHandle
1420 [MonoTODO ("Be able to handle negative dates... i.e. BCE.")]
1421 private DateTime UnpackDate (byte[] bytes)
1423 byte century = bytes [0];
1424 byte year = bytes [1];
1425 byte month = bytes [2];
1426 byte day = bytes [3];
1427 byte hour = bytes [4];
1428 byte minute = bytes [5];
1429 byte second = bytes [6];
1432 return new DateTime ((century - 100) * 100 + (year - 100),
1441 private byte[] PackDate (DateTime dateValue)
1443 byte[] buffer = new byte[7];
1445 buffer[0] = (byte)((dateValue.Year / 100) + 100); //century
1446 buffer[1] = (byte)((dateValue.Year % 100) + 100); // Year
1447 buffer[2] = (byte)dateValue.Month;
1448 buffer[3] = (byte)dateValue.Day;
1449 buffer[4] = (byte)(dateValue.Hour+1);
1450 buffer[5] = (byte)(dateValue.Minute+1);
1451 buffer[6] = (byte)(dateValue.Second+1);
1456 #endregion // Methods
1458 internal sealed class OracleParameterConverter : ExpandableObjectConverter
1460 public OracleParameterConverter ()
1465 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
1467 throw new NotImplementedException ();
1471 public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
1473 throw new NotImplementedException ();