internal void FreeHandle () { switch (ociType) { case OciDataType.Clob: case OciDataType.Blob: lobLocator = null; break; case OciDataType.TimeStamp: break; default: Marshal.FreeHGlobal (bindOutValue); break; } bindOutValue = IntPtr.Zero; bindValue = IntPtr.Zero; bindHandle = null; connection = null; }
internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos) { connection = con; if (bindHandle == null) bindHandle = new OciBindHandle ((OciHandle) statement); IntPtr tmpHandle = bindHandle.Handle; if (Direction != ParameterDirection.Input) AssertSizeIsSet (); if (!sizeSet) size = InferSize (); bindSize = size; object v = value; int status = 0; bindType = ociType; int rsize = 0; string svalue; string sDate; DateTime dt; bool isnull = false; int byteCount; byte[] byteArrayLen; if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { if (v == null) isnull = true; else if (v is DBNull) isnull = true; else { INullable mynullable = v as INullable; if (mynullable != null) isnull = mynullable.IsNull; } } if (isnull == true && direction == ParameterDirection.Input) { bindType = OciDataType.VarChar2; bindSize = 0; } else { switch(ociType) { case OciDataType.VarChar2: case OciDataType.String: case OciDataType.VarChar: case OciDataType.Char: case OciDataType.CharZ: case OciDataType.OciString: bindType = OciDataType.String; svalue = "\0"; // convert value from managed type to type to marshal if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { svalue = v.ToString (); if (direction == ParameterDirection.Input && size > 0 && svalue.Length > size) svalue = svalue.Substring(0, size); svalue = svalue.ToString () + '\0'; // convert managed type to memory allocated earlier // in this case using OCIUnicodeToCharSet rsize = 0; // Get size of buffer status = OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize); if (direction == ParameterDirection.Input) bindSize = rsize; else { // this cannot be rsize because you need room for the output after the execute bindSize = Encoding.UTF8.GetMaxByteCount (Size + 1); } // allocate memory based on bind size bytes = new byte [bindSize]; // Fill buffer status = OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize); } else { // for Output and ReturnValue parameters, get size in bytes bindSize = Encoding.UTF8.GetMaxByteCount (size + 1); // allocate memory for oracle to place the results for the Return or Output param bytes = new byte [bindSize]; } break; case OciDataType.Date: bindType = OciDataType.Date; bindSize = 7; // convert value from managed type to type to marshal if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { if (isnull) bytes = new byte [7]; else { sDate = ""; dt = DateTime.MinValue; if (v is String) { sDate = (string) v; dt = DateTime.Parse (sDate); } else if (v is DateTime) dt = (DateTime) v; else if (v is OracleString) { sDate = v.ToString (); dt = DateTime.Parse (sDate); } else if (v is OracleDateTime) { OracleDateTime odt = (OracleDateTime) v; dt = (DateTime) odt.Value; } else throw new NotImplementedException ("For OracleType.DateTime, data type not implemented: " + v.GetType().ToString() + "."); // for Input and InputOuput, create byte array and pack DateTime into it bytes = PackDate (dt); } } else { // allocate 7-byte array for Output and ReturnValue to put date bytes = new byte [7]; } break; case OciDataType.TimeStamp: dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp); if (dateTimeDesc == null) { OciErrorInfo info = connection.ErrorHandle.HandleError (); throw new OracleException (info.ErrorCode, info.ErrorMessage); } dateTimeDesc.ErrorHandle = connection.ErrorHandle; bindSize = 11; bindType = OciDataType.TimeStamp; bindOutValue = dateTimeDesc.Handle; bindValue = dateTimeDesc.Handle; useRef = true; if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { dt = DateTime.MinValue; sDate = ""; if (isnull) Indicator = -1; else if (v is String) { sDate = (string) v; dt = DateTime.Parse (sDate); } else if (v is DateTime) dt = (DateTime) v; else if (v is OracleString) { sDate = (string) v; dt = DateTime.Parse (sDate); } else if (v is OracleDateTime) { OracleDateTime odt = (OracleDateTime) v; dt = (DateTime) odt.Value; } else throw new NotImplementedException ("For OracleType.Timestamp, data type not implemented: " + v.GetType().ToString()); // ? short year = (short) dt.Year; byte month = (byte) dt.Month; byte day = (byte) dt.Day; byte hour = (byte) dt.Hour; byte min = (byte) dt.Minute; byte sec = (byte) dt.Second; uint fsec = (uint) dt.Millisecond; string timezone = ""; dateTimeDesc.SetDateTime (connection.Session, connection.ErrorHandle, year, month, day, hour, min, sec, fsec, timezone); } break; case OciDataType.Integer: case OciDataType.Float: case OciDataType.Number: bindType = OciDataType.String; Indicator = 0; svalue = "\0"; // convert value from managed type to type to marshal if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { svalue = null; if(v is IFormattable) svalue = ((IFormattable)v).ToString (null, con.SessionFormatProvider); else if (v is OracleNumber) svalue = ((OracleNumber)v).ToString(con.SessionFormatProvider); else svalue = v.ToString(); svalue = svalue + "\0"; rsize = 0; // Get size of buffer OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize); // Fill buffer if (direction == ParameterDirection.Input) bindSize = rsize; else bindSize = 30; // need room for output possibly being bigger than the input bytes = new byte [bindSize]; OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize); } else { // Output and ReturnValue parameters allocate memory bindSize = 30; bytes = new byte [bindSize]; } break; case OciDataType.Long: case OciDataType.LongVarChar: bindType = OciDataType.LongVarChar; // FIXME: use piecewise fetching for Long, Clob, Blob, and Long Raw // See http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci05bnd.htm#sthref724 bindSize = Size + 5; // 4 bytes prepended for length, bytes, 1 byte NUL character Indicator = 0; svalue = "\0"; // convert value from managed type to type to marshal if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { svalue = v.ToString () + '\0'; } bytes = new byte [bindSize]; // LONG is only ANSI ASCIIEncoding enc = new ASCIIEncoding (); if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { if (svalue.Length > 0) { byteCount = enc.GetBytes (svalue, 4, svalue.Length, bytes, 0); // LONG VARCHAR prepends a 4-byte length if (byteCount > 0) { byteArrayLen = BitConverter.GetBytes ((uint) byteCount); bytes[0] = byteArrayLen[0]; bytes[1] = byteArrayLen[1]; bytes[2] = byteArrayLen[2]; bytes[3] = byteArrayLen[3]; } } } break; case OciDataType.Clob: if (direction == ParameterDirection.Input) { svalue = v.ToString(); rsize = 0; // Get size of buffer OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize); // Fill buffer bytes = new byte[rsize]; OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize); bindType = OciDataType.Long; bindSize = bytes.Length; } else if (direction == ParameterDirection.InputOutput) { // not the exact error that .net 2.0 throws, but this is better throw new NotImplementedException ("Parameters of OracleType.Clob with direction of InputOutput are not supported."); } else { // Output and Return parameters bindSize = -1; lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator); if (lobLocator == null) { OciErrorInfo info = connection.ErrorHandle.HandleError (); throw new OracleException (info.ErrorCode, info.ErrorMessage); } bindOutValue = lobLocator.Handle; bindValue = lobLocator.Handle; lobLocator.ErrorHandle = connection.ErrorHandle; lobLocator.Service = statement.Service; lobLocator.Environment = connection.Environment; useRef = true; } break; case OciDataType.Blob: if (direction == ParameterDirection.Input) { if (v is byte[]) { bytes = (byte[]) v; bindType = OciDataType.LongRaw; bindSize = bytes.Length; } else if (v is OracleLob) { OracleLob lob = (OracleLob) v; if (lob.LobType == OracleType.Blob) { lobLocator = lob.Locator; bindOutValue = lobLocator.Handle; bindValue = lobLocator.Handle; lobLocator.ErrorHandle = connection.ErrorHandle; lobLocator.Service = connection.ServiceContext; useRef = true; } else throw new NotImplementedException("For OracleType.Blob, data type OracleLob of LobType Clob/NClob is not implemented."); } else throw new NotImplementedException ("For OracleType.Blob, data type not implemented: " + v.GetType().ToString()); // ? } else if (direction == ParameterDirection.InputOutput) { // not the exact error that .net 2.0 throws, but this is better throw new NotImplementedException ("Parameters of OracleType.Blob with direction of InputOutput are not supported."); } else { bindSize = -1; if (value != null && value is OracleLob) { OracleLob blob = (OracleLob) value; if (blob.LobType == OracleType.Blob) if (value != OracleLob.Null) { lobLocator = blob.Locator; byte[] bs = (byte[]) blob.Value; bindSize = bs.Length; } } if (lobLocator == null) { lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator); if (lobLocator == null) { OciErrorInfo info = connection.ErrorHandle.HandleError (); throw new OracleException (info.ErrorCode, info.ErrorMessage); } } bindOutValue = lobLocator.Handle; bindValue = lobLocator.Handle; lobLocator.ErrorHandle = connection.ErrorHandle; lobLocator.Service = connection.ServiceContext; lobLocator.Environment = connection.Environment; useRef = true; } break; case OciDataType.Raw: case OciDataType.VarRaw: bindType = OciDataType.VarRaw; bindSize = Size + 2; // include 2 bytes prepended to hold the length Indicator = 0; bytes = new byte [bindSize]; if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { byteCount = 0; byte[] val; if (dbType == DbType.Guid) val = ((Guid)v).ToByteArray(); else val = v as byte[]; if (val.Length > 0) { byteCount = val.Length; // LONG VARRAW prepends a 4-byte length if (byteCount > 0) { byteArrayLen = BitConverter.GetBytes ((ushort) byteCount); bytes[0] = byteArrayLen[0]; bytes[1] = byteArrayLen[1]; Array.ConstrainedCopy (val, 0, bytes, 2, byteCount); } } } break; case OciDataType.LongRaw: case OciDataType.LongVarRaw: bindType = OciDataType.LongVarRaw; bindSize = Size + 4; // include 4 bytes prepended to hold the length Indicator = 0; bytes = new byte [bindSize]; if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { byteCount = 0; byte[] val = v as byte[]; if (val.Length > 0) { byteCount = val.Length; // LONG VARRAW prepends a 4-byte length if (byteCount > 0) { byteArrayLen = BitConverter.GetBytes ((uint) byteCount); bytes[0] = byteArrayLen[0]; bytes[1] = byteArrayLen[1]; bytes[2] = byteArrayLen[2]; bytes[3] = byteArrayLen[3]; Array.ConstrainedCopy (val, 0, bytes, 4, byteCount); } } } break; case OciDataType.RowIdDescriptor: if (direction == ParameterDirection.Output || direction == ParameterDirection.InputOutput || direction == ParameterDirection.ReturnValue) { size = 10; bindType = OciDataType.Char; bindSize = size * 2; bindOutValue = OciCalls.AllocateClear (bindSize); bindValue = bindOutValue; } else throw new NotImplementedException("data type RowIdDescriptor as Intput parameters"); break; case OciDataType.RSet: // REF CURSOR if (direction == ParameterDirection.Output || direction == ParameterDirection.InputOutput || direction == ParameterDirection.ReturnValue) { if (cursor != IntPtr.Zero) { OciCalls.OCIHandleFree (cursor, OciHandleType.Statement); cursor = IntPtr.Zero; } OciCalls.OCIHandleAlloc (connection.Environment, out cursor, OciHandleType.Statement, 0, IntPtr.Zero); bindSize = 0; bindType = OciDataType.RSet; } else throw new NotImplementedException ("data type Ref Cursor not implemented for Input parameters"); break; default: throw new NotImplementedException ("Data Type not implemented: " + ociType.ToString() + "."); } } // Now, call the appropriate OCI Bind function; if (useRef == true) { if (bindType == OciDataType.TimeStamp) { bindValue = dateTimeDesc.Handle; status = OciCalls.OCIBindByNameRef (statement, out tmpHandle, connection.ErrorHandle, ParameterName, ParameterName.Length, ref bindValue, bindSize, bindType, indicator, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); } else { status = OciCalls.OCIBindByNameRef (statement, out tmpHandle, connection.ErrorHandle, ParameterName, ParameterName.Length, ref bindValue, bindSize, bindType, indicator, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); } } else if (bindType == OciDataType.RSet) { status = OciCalls.OCIBindByNameRef (statement, out tmpHandle, connection.ErrorHandle, ParameterName, ParameterName.Length, ref cursor, bindSize, bindType, indicator, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); } else if (bytes != null) { status = OciCalls.OCIBindByNameBytes (statement, out tmpHandle, connection.ErrorHandle, ParameterName, ParameterName.Length, bytes, bindSize, bindType, indicator, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); } else { status = OciCalls.OCIBindByName (statement, out tmpHandle, connection.ErrorHandle, ParameterName, ParameterName.Length, // FIXME: this should be in bytes! bindValue, bindSize, bindType, indicator, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); } OciErrorHandle.ThrowExceptionIfError (connection.ErrorHandle, status); bindHandle.SetHandle (tmpHandle); }
internal void Bind (OciStatementHandle statement, OracleConnection connection) { if (bindHandle == null) bindHandle = new OciBindHandle ((OciHandle) statement); IntPtr tmpHandle = bindHandle.Handle; if (Direction != ParameterDirection.Input) AssertSizeIsSet (); if (!sizeSet) size = InferSize (); byte[] bytes = null; int status = 0; int indicator = 0; OciDataType bindType = ociType; IntPtr bindValue = IntPtr.Zero; int bindSize = size; int rsize = 0; if (value == DBNull.Value) { indicator = 0; bindType = OciDataType.VarChar2; bindSize = 0; } else { // TODO: do other data types and oracle data types // should I be using IConvertible to convert? if (oracleType == OracleType.DateTime) { string oraDateFormat = connection.GetSessionDateFormat (); string sysDateFormat = OracleDateTime.ConvertOracleDateFormatToSystemDateTime (oraDateFormat); string sDate = ""; DateTime dt = DateTime.MinValue; if (value is String) { sDate = (string) value; dt = DateTime.Parse (sDate); } else if (value is DateTime) dt = (DateTime) value; else if (value is OracleString) { sDate = (string) value; dt = DateTime.Parse (sDate); } else if (value is OracleDateTime) { OracleDateTime odt = (OracleDateTime) value; dt = (DateTime) odt.Value; } else throw new NotImplementedException (); // ? sDate = dt.ToString (sysDateFormat); rsize = 0; // Get size of buffer OciCalls.OCIUnicodeToCharSet (statement.Parent, null, sDate, out rsize); // Fill buffer bytes = new byte[rsize]; OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, sDate, out rsize); bindType = OciDataType.VarChar2; //bindValue = Marshal.StringToHGlobalAnsi (sDate); bindSize = sDate.Length; } else if (oracleType == OracleType.Blob) { bytes = (byte[]) value; bindType = OciDataType.LongRaw; bindSize = bytes.Length; } else if (oracleType == OracleType.Clob) { string v = (string) value; rsize = 0; // Get size of buffer OciCalls.OCIUnicodeToCharSet (statement.Parent, null, v, out rsize); // Fill buffer bytes = new byte[rsize]; OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, v, out rsize); bindType = OciDataType.Long; bindSize = bytes.Length; } else if (oracleType == OracleType.Raw) { byte[] val = value as byte[]; bindValue = Marshal.AllocHGlobal (val.Length); Marshal.Copy (val, 0, bindValue, val.Length); bindSize = val.Length; } else { string svalue = value.ToString (); rsize = 0; // Get size of buffer OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize); // Fill buffer bytes = new byte[rsize]; OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize); //bindValue = Marshal.StringToHGlobalAnsi (value.ToString ()); bindType = OciDataType.VarChar2; bindSize = value.ToString ().Length; } } if (bytes != null) { status = OciCalls.OCIBindByNameBytes (statement, out tmpHandle, connection.ErrorHandle, ParameterName, ParameterName.Length, bytes, bindSize, bindType, indicator, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); } else { status = OciCalls.OCIBindByName (statement, out tmpHandle, connection.ErrorHandle, ParameterName, ParameterName.Length, bindValue, bindSize, bindType, indicator, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); } if (status != 0) { OciErrorInfo info = connection.ErrorHandle.HandleError (); throw new OracleException (info.ErrorCode, info.ErrorMessage); } bindHandle.SetHandle (tmpHandle); }