| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- //
- // OciDefineHandle.cs
- //
- // Part of managed C#/.NET library System.Data.OracleClient.dll
- //
- // Part of the Mono class libraries at
- // mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci
- //
- // Assembly: System.Data.OracleClient.dll
- // Namespace: System.Data.OracleClient.Oci
- //
- // Authors:
- // Tim Coleman <[email protected]>
- // Daniel Morgan <[email protected]>
- //
- // Copyright (C) Tim Coleman, 2003
- // Copyright (C) Daniel Morgan, 2004
- //
- using System;
- using System.Data.OracleClient;
- using System.Runtime.InteropServices;
- using System.Text;
- namespace System.Data.OracleClient.Oci
- {
- internal sealed class OciDefineHandle : OciHandle, IDisposable
- {
- #region Fields
- bool disposed = false;
- IntPtr handle;
- IntPtr value;
- short indicator;
- OracleType type;
- OciDataType ociType;
- OciDataType definedType;
- int definedSize;
- short rlenp = 0;
- short precision;
- short scale;
- Type fieldType;
- string name;
- // Oracle defines the LONG VARCHAR have a size of 2 to the 31 power - 5
- // maybe this should settable via a config file for System.Data.OracleClient.dll
- // see DefineLong. Or if the a truncate sql error occurs, then retry?
- // or maybe allocate the memory yourself and then let oracle return error more data,
- // then try to get some more data
- internal static int LongVarCharMaxValue = (int) Int16.MaxValue - 5;
- OciErrorHandle errorHandle;
- OciLobLocator lobLocator;
- byte[] date;
-
- #endregion // Fields
- #region Constructors
- public OciDefineHandle (OciHandle parent, IntPtr newHandle)
- : base (OciHandleType.Define, parent, newHandle)
- {
- }
- public void DefineByPosition (int position)
- {
- OciParameterDescriptor parameter = ((OciStatementHandle) Parent).GetParameter (position);
-
- name = parameter.GetName ();
- definedType = parameter.GetDataType ();
- definedSize = parameter.GetDataSize ();
- precision = parameter.GetPrecision ();
- scale = parameter.GetScale ();
- Define (position);
- parameter.Dispose ();
- }
- #endregion // Constructors
- #region Properties
- public OciDataType DataType {
- get { return definedType; }
- }
- public Type FieldType {
- get { return fieldType; }
- }
- public int DefinedSize {
- get { return definedSize; }
- }
- public OciErrorHandle ErrorHandle {
- get { return errorHandle; }
- set { errorHandle = value; }
- }
- public bool IsNull {
- get { return (indicator == -1); }
- }
- public short Scale {
- get { return scale; }
- }
- public short Size {
- get { return rlenp; }
- }
- public IntPtr Value {
- get { return value; }
- }
- #endregion
- #region Methods
- void Define (int position)
- {
- switch (definedType) {
- case OciDataType.Date:
- DefineDate (position);
- return;
- case OciDataType.Clob:
- case OciDataType.Blob:
- DefineLob (position, definedType);
- return;
- case OciDataType.Raw:
- DefineRaw( position);
- return;
- case OciDataType.RowIdDescriptor:
- definedSize = 10;
- DefineChar (position);
- return;
- case OciDataType.Integer:
- case OciDataType.Number:
- case OciDataType.Float:
- DefineNumber (position);
- return;
- case OciDataType.Long:
- case OciDataType.LongVarChar:
- DefineLong (position);
- return;
- default:
- DefineChar (position); // HANDLE ALL OTHERS AS CHAR FOR NOW
- return;
- }
- }
- void DefineDate (int position)
- {
- definedSize = 7;
- ociType = OciDataType.Date;
- fieldType = typeof(System.DateTime);
- value = Marshal.AllocHGlobal (definedSize);
- int status = 0;
- status = OciCalls.OCIDefineByPos (Parent,
- out handle,
- ErrorHandle,
- position + 1,
- value,
- definedSize,
- ociType,
- ref indicator,
- ref rlenp,
- IntPtr.Zero,
- 0);
- if (status != 0) {
- OciErrorInfo info = ErrorHandle.HandleError ();
- throw new OracleException (info.ErrorCode, info.ErrorMessage);
- }
- }
- void DefineLong (int position)
- {
- fieldType = typeof (System.String);
- // LONG VARCHAR max length is 2 to the 31 power - 5
- // the first 4 bytes of a LONG VARCHAR value contains the length
- // Int32.MaxValue - 5 causes out of memory in mono on win32
- // because I do not have 2GB of memory available
- // so Int16.MaxValue - 5 is used instead.
- // LAMESPEC for Oracle OCI - you can not get the length of the LONG VARCHAR value
- // until after you get the value. This could be why Oracle deprecated LONG VARCHAR.
- // If you specify a definedSize less then the length of the column value,
- // then you will get an OCI_ERROR ORA-01406: fetched column value was truncated
- definedSize = LongVarCharMaxValue;
-
- value = Marshal.AllocHGlobal (definedSize);
- ociType = OciDataType.LongVarChar;
- int status = 0;
- status = OciCalls.OCIDefineByPos (Parent,
- out handle,
- ErrorHandle,
- position + 1,
- value,
- definedSize,
- ociType,
- ref indicator,
- ref rlenp,
- IntPtr.Zero, 0);
- rlenp = (short) definedSize;
- if (status != 0) {
- OciErrorInfo info = ErrorHandle.HandleError ();
- throw new OracleException (info.ErrorCode, info.ErrorMessage);
- }
- }
- void DefineChar (int position)
- {
- fieldType = typeof (System.String);
- // The buffer is able to contain twice the defined size
- // to allow usage of multibyte characters
- value = Marshal.AllocHGlobal (definedSize * 2);
- ociType = OciDataType.Char;
- int status = 0;
-
- status = OciCalls.OCIDefineByPos (Parent,
- out handle,
- ErrorHandle,
- position + 1,
- value,
- definedSize * 2,
- ociType,
- ref indicator,
- ref rlenp,
- IntPtr.Zero,
- 0);
- if (status != 0) {
- OciErrorInfo info = ErrorHandle.HandleError ();
- throw new OracleException (info.ErrorCode, info.ErrorMessage);
- }
- }
- void DefineNumber (int position)
- {
- fieldType = typeof (System.Decimal);
- value = Marshal.AllocHGlobal (definedSize);
- ociType = OciDataType.Char;
- int status = 0;
-
- status = OciCalls.OCIDefineByPos (Parent,
- out handle,
- ErrorHandle,
- position + 1,
- value,
- definedSize * 2,
- ociType,
- ref indicator,
- ref rlenp,
- IntPtr.Zero,
- 0);
- if (status != 0) {
- OciErrorInfo info = ErrorHandle.HandleError ();
- throw new OracleException (info.ErrorCode, info.ErrorMessage);
- }
- }
- void DefineLob (int position, OciDataType type)
- {
- ociType = type;
- if (ociType == OciDataType.Clob)
- fieldType = typeof(System.String);
- else if (ociType == OciDataType.Blob)
- fieldType = Type.GetType("System.Byte[]");
- int status = 0;
- definedSize = -1;
- lobLocator = (OciLobLocator) Parent.Parent.Allocate (OciHandleType.LobLocator);
- if (lobLocator == null) {
- OciErrorInfo info = ErrorHandle.HandleError ();
- throw new OracleException (info.ErrorCode, info.ErrorMessage);
- }
- value = lobLocator.Handle;
- lobLocator.ErrorHandle = ErrorHandle;
- lobLocator.Service = ((OciStatementHandle) Parent).Service;
- status = OciCalls.OCIDefineByPosPtr (Parent,
- out handle,
- ErrorHandle,
- position + 1,
- ref value,
- definedSize,
- ociType,
- ref indicator,
- ref rlenp,
- IntPtr.Zero,
- 0);
- definedSize = Int32.MaxValue;
- if (status != 0) {
- OciErrorInfo info = ErrorHandle.HandleError ();
- throw new OracleException (info.ErrorCode, info.ErrorMessage);
- }
- }
- void DefineRaw (int position)
- {
- ociType = OciDataType.Raw;
- fieldType = Type.GetType("System.Byte[]");
- value = Marshal.AllocHGlobal (definedSize);
- int status = 0;
- status = OciCalls.OCIDefineByPos (Parent,
- out handle,
- ErrorHandle,
- position + 1,
- value,
- definedSize * 2,
- ociType,
- ref indicator,
- ref rlenp,
- IntPtr.Zero, 0);
- if (status != 0) {
- OciErrorInfo info = ErrorHandle.HandleError ();
- throw new OracleException (info.ErrorCode, info.ErrorMessage);
- }
- }
- protected override void Dispose (bool disposing)
- {
- if (!disposed) {
- try {
- switch (definedType) {
- case OciDataType.Clob:
- case OciDataType.Blob:
- break;
- default:
- Marshal.FreeHGlobal (value);
- break;
- }
- disposed = true;
- } finally {
- base.Dispose (disposing);
- value = IntPtr.Zero;
- }
- }
- }
- public OracleLob GetOracleLob ()
- {
- return new OracleLob (lobLocator, ociType);
- }
- public object GetValue ()
- {
- object tmp;
- byte [] buffer = null;
- switch (DataType) {
- case OciDataType.VarChar2:
- case OciDataType.String:
- case OciDataType.VarChar:
- case OciDataType.Char:
- case OciDataType.CharZ:
- case OciDataType.OciString:
- case OciDataType.RowIdDescriptor:
- buffer = new byte [Size];
- Marshal.Copy (Value, buffer, 0, Size);
-
- // Get length of returned string
- int rsize = 0;
- IntPtr env = Parent.Parent; // Parent is statement, grandparent is environment
- OciCalls.OCICharSetToUnicode (env, null, buffer, out rsize);
-
- // Get string
- StringBuilder ret = new StringBuilder(rsize);
- OciCalls.OCICharSetToUnicode (env, ret, buffer, out rsize);
-
- return ret.ToString ();
- case OciDataType.LongVarChar:
- case OciDataType.Long:
- buffer = new byte [LongVarCharMaxValue];
- Marshal.Copy (Value, buffer, 0, buffer.Length);
-
- int longSize = 0;
- if (BitConverter.IsLittleEndian)
- longSize = BitConverter.ToInt32 (new byte[]{buffer[0], buffer[1], buffer[2], buffer[3]}, 0);
- else
- longSize = BitConverter.ToInt32 (new byte[]{buffer[3], buffer[2], buffer[1], buffer[0]}, 0);
- ASCIIEncoding encoding = new ASCIIEncoding ();
- string e = encoding.GetString (buffer, 4, longSize);
- return e;
- case OciDataType.Integer:
- case OciDataType.Number:
- case OciDataType.Float:
- tmp = Marshal.PtrToStringAnsi (Value, Size);
- if (tmp != null)
- return Decimal.Parse (String.Copy ((string) tmp));
- break;
- case OciDataType.Date:
- return UnpackDate ();
- case OciDataType.Raw:
- byte [] raw_buffer = new byte [Size];
- Marshal.Copy (Value, raw_buffer, 0, Size);
- return raw_buffer;
- case OciDataType.Blob:
- case OciDataType.Clob:
- return GetOracleLob ();
- }
- return DBNull.Value;
- }
- internal object GetOracleValue ()
- {
- object ovalue = GetValue ();
- switch (DataType) {
- case OciDataType.Raw:
- return new OracleBinary ((byte[]) ovalue);
- case OciDataType.Date:
- return new OracleDateTime ((DateTime) ovalue);
- case OciDataType.Blob:
- case OciDataType.Clob:
- OracleLob lob = (OracleLob) ovalue;
- return lob;
- case OciDataType.Integer:
- case OciDataType.Number:
- case OciDataType.Float:
- return new OracleNumber ((decimal) ovalue);
- case OciDataType.VarChar2:
- case OciDataType.String:
- case OciDataType.VarChar:
- case OciDataType.Char:
- case OciDataType.CharZ:
- case OciDataType.OciString:
- case OciDataType.LongVarChar:
- case OciDataType.Long:
- case OciDataType.RowIdDescriptor:
- return new OracleString ((string) ovalue);
- default:
- // TODO: do other types
- throw new NotImplementedException ();
- }
- }
- [MonoTODO ("Be able to handle negative dates... i.e. BCE.")]
- internal DateTime UnpackDate ()
- {
- byte century = Marshal.ReadByte (value, 0);
- byte year = Marshal.ReadByte (value, 1);
- byte month = Marshal.ReadByte (value, 2);
- byte day = Marshal.ReadByte (value, 3);
- byte hour = Marshal.ReadByte (value, 4);
- byte minute = Marshal.ReadByte (value, 5);
- byte second = Marshal.ReadByte (value, 6);
- return new DateTime ((century - 100) * 100 + (year - 100),
- month,
- day,
- hour - 1,
- minute - 1,
- second - 1);
- }
- #endregion // Methods
- }
- }
|