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 <danielmorgan@verizon.net>
13 // Hubert FONGARNAND <informatique.internet@fiducial.fr>
15 // Copyright (C) Tim Coleman , 2003
16 // Copyright (C) Daniel Morgan, 2005
17 // Copyright (C) Hubert FONGARNAND, 2005
19 // Licensed under the MIT/X11 License.
23 using System.Collections;
24 using System.ComponentModel;
26 using System.Data.SqlTypes;
27 using System.Data.OracleClient.Oci;
28 using System.Globalization;
29 using System.Runtime.InteropServices;
32 namespace System.Data.OracleClient {
33 [TypeConverter (typeof(OracleParameter.OracleParameterConverter))]
34 public sealed class OracleParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
39 OracleType oracleType = OracleType.VarChar;
42 ParameterDirection direction = ParameterDirection.Input;
47 DataRowVersion srcVersion;
48 DbType dbType = DbType.AnsiString;
51 object value = DBNull.Value;
52 OciLobLocator lobLocator = null; // only if Blob or Clob
53 IntPtr bindOutValue = IntPtr.Zero;
54 OciDateTimeDescriptor dateTimeDesc = null;
55 IntPtr cursor = IntPtr.Zero;
57 OracleParameterCollection container = null;
58 OciBindHandle bindHandle;
59 OciErrorHandle errorHandle;
60 OracleConnection connection;
62 IntPtr bindValue = IntPtr.Zero;
66 short indicator = 0; // TODO: handle indicator to indicate NULL value for OUT parameters
74 // constructor for cloning the object
75 internal OracleParameter (OracleParameter value) {
76 this.name = value.name;
77 this.oracleType = value.oracleType;
78 this.ociType = value.ociType;
79 this.size = value.size;
80 this.direction = value.direction;
81 this.isNullable = value.isNullable;
82 this.precision = value.precision;
83 this.scale = value.scale;
84 this.srcColumn = value.srcColumn;
85 this.srcVersion = value.srcVersion;
86 this.dbType = value.dbType;
87 this.offset = value.offset;
88 this.sizeSet = value.sizeSet;
89 this.value = value.value;
90 this.lobLocator = value.lobLocator;
93 public OracleParameter ()
94 : this (String.Empty, OracleType.VarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
98 public OracleParameter (string name, object value)
102 SourceVersion = DataRowVersion.Current;
103 InferOracleType (value);
106 public OracleParameter (string name, OracleType dataType)
107 : this (name, dataType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
111 public OracleParameter (string name, OracleType dataType, int size)
112 : this (name, dataType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
116 public OracleParameter (string name, OracleType dataType, int size, string srcColumn)
117 : this (name, dataType, size, ParameterDirection.Input, false, 0, 0, srcColumn, DataRowVersion.Current, null)
121 public OracleParameter (string name, OracleType dataType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string srcColumn, DataRowVersion srcVersion, object value)
127 OracleType = dataType;
128 Direction = direction;
129 SourceColumn = srcColumn;
130 SourceVersion = srcVersion;
133 #endregion // Constructors
137 internal OracleParameterCollection Container {
138 get { return container; }
139 set { container = value; }
143 [RefreshProperties (RefreshProperties.All)]
144 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
145 public DbType DbType {
146 get { return dbType; }
147 set { SetDbType (value); }
150 [DefaultValue (ParameterDirection.Input)]
151 [RefreshProperties (RefreshProperties.All)]
152 public ParameterDirection Direction {
153 get { return direction; }
154 set { direction = value; }
159 [DefaultValue (false)]
160 [EditorBrowsable (EditorBrowsableState.Never)]
161 public bool IsNullable {
162 get { return isNullable; }
163 set { isNullable = value; }
169 get { return offset; }
170 set { offset = value; }
173 [DefaultValue (OracleType.VarChar)]
174 [RefreshProperties (RefreshProperties.All)]
175 public OracleType OracleType {
176 get { return oracleType; }
177 set { SetOracleType (value); }
181 public string ParameterName {
183 set { name = value; }
187 public byte Precision {
188 get { return precision; }
189 set { /* NO EFFECT*/ }
194 get { return scale; }
195 set { /* NO EFFECT*/ }
208 public string SourceColumn {
209 get { return srcColumn; }
210 set { srcColumn = value; }
213 [DefaultValue ("Current")]
214 public DataRowVersion SourceVersion {
215 get { return srcVersion; }
216 set { srcVersion = value; }
219 [DefaultValue (null)]
220 [RefreshProperties (RefreshProperties.All)]
221 [TypeConverter (typeof(StringConverter))]
222 public object Value {
223 get { return this.value; }
224 set { this.value = value; }
227 #endregion // Properties
231 private void AssertSizeIsSet ()
234 case OciDataType.VarChar2:
235 case OciDataType.String:
236 case OciDataType.VarChar:
237 case OciDataType.Char:
238 case OciDataType.CharZ:
239 case OciDataType.OciString:
241 throw new Exception ("Size must be set.");
248 internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos)
252 errorHandle = connection.ErrorHandle;
254 if (bindHandle == null)
255 bindHandle = new OciBindHandle ((OciHandle) statement);
257 IntPtr tmpHandle = bindHandle.Handle;
261 if (Direction != ParameterDirection.Input)
273 if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) {
275 Type nullable = v.GetType ().GetInterface ("System.Data.SqlTypes.INullable", false);
276 if (nullable != null) {
277 INullable mynullable = (INullable)v;
278 isnull = mynullable.IsNull;
282 System.IO.TextWriter.Null.WriteLine(e.Message);
286 // TODO: handle InputOutput and Return parameters
287 if (direction == ParameterDirection.Output) {
288 // TODO: need to figure out how OracleParameter
289 // which uses OciBindHandle to share code
290 // with OciDefineHandle
292 case OciDataType.VarChar2:
293 case OciDataType.String:
294 case OciDataType.VarChar:
295 case OciDataType.Char:
296 case OciDataType.CharZ:
297 case OciDataType.OciString:
298 bindType = OciDataType.Char;
300 bindOutValue = Marshal.AllocHGlobal (bindSize);
301 bindValue = bindOutValue;
303 case OciDataType.RowIdDescriptor:
305 bindType = OciDataType.Char;
307 bindOutValue = Marshal.AllocHGlobal (bindSize);
308 bindValue = bindOutValue;
310 case OciDataType.Date:
312 bindType = OciDataType.Date;
313 bindOutValue = Marshal.AllocHGlobal (bindSize);
314 bindValue = bindOutValue;
316 case OciDataType.TimeStamp:
317 dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
318 if (dateTimeDesc == null) {
319 OciErrorInfo info = connection.ErrorHandle.HandleError ();
320 throw new OracleException (info.ErrorCode, info.ErrorMessage);
322 dateTimeDesc.ErrorHandle = connection.ErrorHandle;
324 bindType = OciDataType.TimeStamp;
325 bindOutValue = dateTimeDesc.Handle;
326 bindValue = dateTimeDesc.Handle;
329 case OciDataType.Number:
331 bindType = OciDataType.Char;
332 bindOutValue = Marshal.AllocHGlobal (bindSize);
333 bindValue = bindOutValue;
335 case OciDataType.Long:
336 case OciDataType.LongVarChar:
337 // LAMESPEC: you don't know size until you get it;
338 // therefore, you must allocate an insane size
339 // see OciDefineHandle
340 bindSize = OciDefineHandle.LongVarCharMaxValue;
341 bindOutValue = Marshal.AllocHGlobal (bindSize);
342 bindType = OciDataType.LongVarChar;
343 bindValue = bindOutValue;
345 case OciDataType.Blob:
346 case OciDataType.Clob:
348 lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
349 if (lobLocator == null) {
350 OciErrorInfo info = connection.ErrorHandle.HandleError ();
351 throw new OracleException (info.ErrorCode, info.ErrorMessage);
353 bindOutValue = lobLocator.Handle;
354 bindValue = lobLocator.Handle;
355 lobLocator.ErrorHandle = connection.ErrorHandle;
356 lobLocator.Service = statement.Service;
359 case OciDataType.RSet: // REF CURSOR
360 cursor = IntPtr.Zero;
361 OciCalls.OCIHandleAlloc (connection.Environment,
363 OciHandleType.Statement,
368 bindType = OciDataType.RSet;
371 // define other types
372 throw new NotImplementedException ();
374 bindValue = bindOutValue;
376 else if ((v == DBNull.Value || v == null || isnull == true) && direction == ParameterDirection.Input) {
378 bindType = OciDataType.VarChar2;
382 // TODO: do other data types and oracle data types
383 // should I be using IConvertible to convert?
385 DateTime dt = DateTime.MinValue;
386 if (oracleType == OracleType.Timestamp){
387 bindType = OciDataType.TimeStamp;
389 dt = DateTime.MinValue;
393 dt = DateTime.Parse (sDate);
395 else if (v is DateTime)
397 else if (v is OracleString){
399 dt = DateTime.Parse (sDate);
401 else if (v is OracleDateTime) {
402 OracleDateTime odt = (OracleDateTime) v;
403 dt = (DateTime) odt.Value;
406 throw new NotImplementedException (); // ?
408 short year = (short) dt.Year;
409 byte month = (byte) dt.Month;
410 byte day = (byte) dt.Day;
411 byte hour = (byte) dt.Hour;
412 byte min = (byte) dt.Minute;
413 byte sec = (byte) dt.Second;
414 uint fsec = (uint) dt.Millisecond;
415 string timezone = "";
416 dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
417 if (dateTimeDesc == null) {
418 OciErrorInfo info = connection.ErrorHandle.HandleError ();
419 throw new OracleException (info.ErrorCode, info.ErrorMessage);
421 dateTimeDesc.ErrorHandle = connection.ErrorHandle;
422 dateTimeDesc.SetDateTime (connection.Session,
423 connection.ErrorHandle,
424 year, month, day, hour, min, sec, fsec,
428 else if (oracleType == OracleType.DateTime) {
430 dt = DateTime.MinValue;
433 dt = DateTime.Parse (sDate);
435 else if (v is DateTime)
437 else if (v is OracleString) {
439 dt = DateTime.Parse (sDate);
441 else if (v is OracleDateTime) {
442 OracleDateTime odt = (OracleDateTime) v;
443 dt = (DateTime) odt.Value;
446 throw new NotImplementedException (); // ?
448 bytes = PackDate (dt);
449 bindType = OciDataType.Date;
450 bindSize = bytes.Length;
452 else if (oracleType == OracleType.Blob) {
454 bindType = OciDataType.LongRaw;
455 bindSize = bytes.Length;
457 else if (oracleType == OracleType.Clob) {
458 string sv = v.ToString();
461 // Get size of buffer
462 OciCalls.OCIUnicodeToCharSet (statement.Parent, null, sv, out rsize);
465 bytes = new byte[rsize];
466 OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, sv, out rsize);
468 bindType = OciDataType.Long;
469 bindSize = bytes.Length;
471 else if (oracleType == OracleType.Raw) {
472 byte[] val = v as byte[];
473 bindValue = Marshal.AllocHGlobal (val.Length);
474 Marshal.Copy (val, 0, bindValue, val.Length);
475 bindSize = val.Length;
477 else if (oracleType == OracleType.Number
478 || oracleType == OracleType.Double
479 || oracleType == OracleType.Int32
480 || oracleType == OracleType.Int16
481 || oracleType == OracleType.Byte
482 || oracleType == OracleType.Float) {
483 string svalue = null;
484 if(v is IFormattable)
485 svalue = ((IFormattable)v).ToString (null, con.SessionFormatProvider);
487 svalue = v.ToString();
490 // Get size of buffer
491 OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
494 bytes = new byte[rsize];
495 OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
497 bindType = OciDataType.VarChar2;
498 bindSize = svalue.Length;
501 string svalue = v.ToString () + '\0';
504 // Get size of buffer
505 OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
508 bytes = new byte[rsize];
509 OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
511 bindType = OciDataType.String;
512 bindSize = svalue.Length;
516 // Now, call the appropriate OCI Bind function
518 if (useRef == true) {
519 if (bindType == OciDataType.TimeStamp) {
520 bindValue = dateTimeDesc.Handle;
521 status = OciCalls.OCIBindByNameRef (statement,
523 connection.ErrorHandle,
525 ParameterName.Length,
537 status = OciCalls.OCIBindByNameRef (statement,
539 connection.ErrorHandle,
541 ParameterName.Length,
553 else if (bindType == OciDataType.RSet) {
554 status = OciCalls.OCIBindByNameRef (statement,
556 connection.ErrorHandle,
558 ParameterName.Length,
569 else if (bytes != null) {
570 status = OciCalls.OCIBindByNameBytes (statement,
572 connection.ErrorHandle,
574 ParameterName.Length,
586 status = OciCalls.OCIBindByName (statement,
588 connection.ErrorHandle,
590 ParameterName.Length,
603 OciErrorInfo info = connection.ErrorHandle.HandleError ();
604 throw new OracleException (info.ErrorCode, info.ErrorMessage);
607 bindHandle.SetHandle (tmpHandle);
610 object ICloneable.Clone ()
612 return new OracleParameter(this);
615 private void InferOracleType (object value)
617 Type type = value.GetType ();
618 string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
619 switch (type.FullName) {
621 SetOracleType (OracleType.Number);
623 case "System.Boolean":
625 SetOracleType (OracleType.Byte);
627 case "System.String":
628 SetOracleType (OracleType.VarChar);
630 case "System.DateTime":
631 SetOracleType (OracleType.DateTime);
633 case "System.Decimal":
634 SetOracleType (OracleType.Number);
635 //scale = ((decimal) value).Scale;
637 case "System.Double":
638 SetOracleType (OracleType.Double);
640 case "System.Byte[]":
642 SetOracleType (OracleType.Raw);
645 SetOracleType (OracleType.Int32);
647 case "System.Single":
648 SetOracleType (OracleType.Float);
651 SetOracleType (OracleType.Int16);
654 throw new ArgumentException (exception);
658 private int InferSize ()
663 case OciDataType.VarChar2:
664 case OciDataType.String:
665 case OciDataType.VarChar:
666 case OciDataType.Char:
667 case OciDataType.CharZ:
668 case OciDataType.OciString:
669 case OciDataType.Long:
670 case OciDataType.LongVarChar:
671 if (value == null || value == DBNull.Value)
674 newSize = value.ToString ().Length;
676 case OciDataType.RowIdDescriptor:
679 case OciDataType.Integer:
680 case OciDataType.Number:
681 case OciDataType.Float:
684 case OciDataType.Date:
687 case OciDataType.TimeStamp:
690 case OciDataType.Blob:
691 case OciDataType.Clob:
692 case OciDataType.RSet: // REF CURSOR
696 if (value == null || value == DBNull.Value)
699 newSize = value.ToString ().Length;
708 private void SetDbType (DbType type)
710 string exception = String.Format ("No mapping exists from DbType {0} to a known OracleType.", type);
712 case DbType.AnsiString:
713 oracleType = OracleType.VarChar;
714 ociType = OciDataType.VarChar;
716 case DbType.AnsiStringFixedLength:
717 oracleType = OracleType.Char;
718 ociType = OciDataType.Char;
722 oracleType = OracleType.Raw;
723 ociType = OciDataType.Raw;
727 oracleType = OracleType.Byte;
728 ociType = OciDataType.Integer;
730 case DbType.Currency:
733 oracleType = OracleType.Number;
734 ociType = OciDataType.Number;
737 case DbType.DateTime:
739 oracleType = OracleType.DateTime;
740 ociType = OciDataType.Char;
743 oracleType = OracleType.Double;
744 ociType = OciDataType.Float;
747 oracleType = OracleType.Int16;
748 ociType = OciDataType.Integer;
751 oracleType = OracleType.Int32;
752 ociType = OciDataType.Integer;
755 oracleType = OracleType.Blob;
756 ociType = OciDataType.Blob;
759 oracleType = OracleType.Float;
760 ociType = OciDataType.Float;
763 oracleType = OracleType.NVarChar;
764 ociType = OciDataType.VarChar;
766 case DbType.StringFixedLength:
767 oracleType = OracleType.NChar;
768 ociType = OciDataType.Char;
771 throw new ArgumentException (exception);
777 private void SetOracleType (OracleType type)
780 string exception = String.Format ("No mapping exists from OracleType {0} to a known DbType.", type);
782 case OracleType.BFile:
783 case OracleType.Blob:
784 dbType = DbType.Binary;
785 ociType = OciDataType.Blob;
787 case OracleType.LongRaw:
789 dbType = DbType.Binary;
790 ociType = OciDataType.Raw;
792 case OracleType.Byte:
793 dbType = DbType.Byte;
794 ociType = OciDataType.Number;
796 case OracleType.Char:
797 dbType = DbType.AnsiString;
798 ociType = OciDataType.Char;
800 case OracleType.Clob:
801 dbType = DbType.AnsiString;
802 ociType = OciDataType.Clob;
804 case OracleType.LongVarChar:
805 case OracleType.RowId:
806 case OracleType.VarChar:
807 dbType = DbType.AnsiString;
808 ociType = OciDataType.VarChar;
810 case OracleType.Cursor: // REF CURSOR
811 ociType = OciDataType.RSet;
812 dbType = DbType.Object;
814 case OracleType.IntervalDayToSecond:
815 dbType = DbType.AnsiStringFixedLength;
816 ociType = OciDataType.Char;
818 case OracleType.Timestamp:
819 case OracleType.TimestampLocal:
820 case OracleType.TimestampWithTZ:
821 dbType = DbType.DateTime;
822 ociType = OciDataType.TimeStamp;
824 case OracleType.DateTime:
825 dbType = DbType.DateTime;
826 ociType = OciDataType.Date;
828 case OracleType.Double:
829 dbType = DbType.Double;
830 ociType = OciDataType.Number;
832 case OracleType.Float:
833 dbType = DbType.Single;
834 ociType = OciDataType.Number;
836 case OracleType.Int16:
837 dbType = DbType.Int16;
838 ociType = OciDataType.Number;
840 case OracleType.Int32:
841 case OracleType.IntervalYearToMonth:
842 dbType = DbType.Int32;
843 ociType = OciDataType.Number;
845 case OracleType.NChar:
846 dbType = DbType.StringFixedLength;
847 ociType = OciDataType.Char;
849 case OracleType.NClob:
850 case OracleType.NVarChar:
851 dbType = DbType.String;
852 ociType = OciDataType.Char;
854 case OracleType.Number:
855 dbType = DbType.VarNumeric;
856 ociType = OciDataType.Number;
858 case OracleType.SByte:
859 dbType = DbType.SByte;
860 ociType = OciDataType.Number;
862 case OracleType.UInt16:
863 dbType = DbType.UInt16;
864 ociType = OciDataType.Number;
866 case OracleType.UInt32:
867 dbType = DbType.UInt32;
868 ociType = OciDataType.Number;
871 throw new ArgumentException (exception);
877 public override string ToString ()
879 return ParameterName;
882 private void GetOutValue (OracleCommand cmd)
884 // used to update the parameter value
885 // for Output, the output of InputOutput, and Return parameters
886 value = DBNull.Value;
890 byte[] buffer = null;
894 case OciDataType.VarChar2:
895 case OciDataType.String:
896 case OciDataType.VarChar:
897 case OciDataType.Char:
898 case OciDataType.CharZ:
899 case OciDataType.OciString:
900 case OciDataType.RowIdDescriptor:
901 buffer = new byte [Size];
902 Marshal.Copy (bindOutValue, buffer, 0, Size);
904 // Get length of returned string
906 IntPtr env = cmd.Connection.Environment;
907 OciCalls.OCICharSetToUnicode (env, null, buffer, out rsize);
910 StringBuilder ret = new StringBuilder(rsize);
911 OciCalls.OCICharSetToUnicode (env, ret, buffer, out rsize);
913 value = ret.ToString ();
915 case OciDataType.Integer:
916 case OciDataType.Number:
917 case OciDataType.Float:
918 tmp = Marshal.PtrToStringAnsi (bindOutValue, bindSize);
920 value = Decimal.Parse (String.Copy ((string) tmp), cmd.Connection.SessionFormatProvider);
922 case OciDataType.TimeStamp:
923 value = dateTimeDesc.GetDateTime (connection.Environment, dateTimeDesc.ErrorHandle);
925 case OciDataType.Date:
926 value = UnpackDate (bindOutValue);
928 case OciDataType.Blob:
929 case OciDataType.Clob:
930 OracleLob lob = new OracleLob (lobLocator, ociType);
931 lob.connection = connection;
934 case OciDataType.RSet: // REF CURSOR
935 OciStatementHandle cursorStatement = new OciStatementHandle (cmd.Connection.Environment, cursor);
936 cursorStatement.ErrorHandle = cmd.ErrorHandle;
937 cursorStatement.Command = cmd.Connection.CreateCommand ();
938 cursorStatement.SetupRefCursorResult ();
939 value = new OracleDataReader (cursorStatement.Command, cursorStatement, true, CommandBehavior.Default);
940 cursor = IntPtr.Zero;
941 cursorStatement = null;
944 throw new NotImplementedException ();
950 internal void Update (OracleCommand cmd)
952 if (Direction != ParameterDirection.Input)
958 internal void FreeHandle ()
961 case OciDataType.Clob:
962 case OciDataType.Blob:
965 case OciDataType.Raw:
966 Marshal.FreeHGlobal (bindValue);
968 case OciDataType.TimeStamp:
971 Marshal.FreeHGlobal (bindOutValue);
975 bindOutValue = IntPtr.Zero;
976 bindValue = IntPtr.Zero;
983 // copied from OciDefineHandle
984 [MonoTODO ("Be able to handle negative dates... i.e. BCE.")]
985 internal DateTime UnpackDate (IntPtr dateValue)
987 byte century = Marshal.ReadByte (dateValue, 0);
988 byte year = Marshal.ReadByte (dateValue, 1);
989 byte month = Marshal.ReadByte (dateValue, 2);
990 byte day = Marshal.ReadByte (dateValue, 3);
991 byte hour = Marshal.ReadByte (dateValue, 4);
992 byte minute = Marshal.ReadByte (dateValue, 5);
993 byte second = Marshal.ReadByte (dateValue, 6);
995 return new DateTime ((century - 100) * 100 + (year - 100),
1004 internal byte[] PackDate (DateTime dateValue)
1006 byte[] buffer = new byte[7];
1008 buffer[0] = (byte)((dateValue.Year / 100) + 100); //century
1009 buffer[1] = (byte)((dateValue.Year % 100) + 100); // Year
1010 buffer[2] = (byte)dateValue.Month;
1011 buffer[3] = (byte)dateValue.Day;
1012 buffer[4] = (byte)(dateValue.Hour+1);
1013 buffer[5] = (byte)(dateValue.Minute+1);
1014 buffer[6] = (byte)(dateValue.Second+1);
1019 #endregion // Methods
1021 internal sealed class OracleParameterConverter : ExpandableObjectConverter
1023 public OracleParameterConverter ()
1028 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
1030 throw new NotImplementedException ();
1034 public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
1036 throw new NotImplementedException ();