Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / DataOracleClient / System / Data / OracleClient / OracleParameterBinding.cs / 3 / OracleParameterBinding.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// [....]
//-----------------------------------------------------------------------------
namespace System.Data.OracleClient
{
using System;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
//---------------------------------------------------------------------
// OracleParameterBinding
//
// this class is meant to handle the parameter binding for an
// single command object (since parameters can be bound concurrently
// to multiple command objects)
//
sealed internal class OracleParameterBinding {
OracleCommand _command; // the command that this binding is for
OracleParameter _parameter; // the parameter that this binding is for
object _coercedValue; // _parameter.CoercedValue;
MetaType _bindingMetaType; // meta type of the binding, in case it needs adjustment (String bound as CLOB, etc...)
OciBindHandle _bindHandle; // the bind handle, once this has been bound
int _bindSize; // number of bytes/characters to reserve on the server
int _bufferLength; // number of bytes required to bind the value
int _indicatorOffset; // offset from the start of the parameter buffer to the indicator binding (see OCI.INDICATOR)
int _lengthOffset; // offset from the start of the parameter buffer to the length binding
int _valueOffset; // offset from the start of the parameter buffer to the value binding
bool _bindAsUCS2; // true when we should bind this as UCS2
bool _freeTemporaryLob; // true when we've allocated a temporary lob (in _coercedValue) that must be freed.
OciStatementHandle _descriptor; // ref cursor handle for ref cursor types.
OciLobLocator _locator; // lob locator for BFile and Lob types.
OciDateTimeDescriptor _dateTimeDescriptor; // OCI datetime descriptor to hold date time values
// Construct an "empty" parameter
internal OracleParameterBinding (OracleCommand command, OracleParameter parameter) {
_command = command;
_parameter = parameter;
}
internal OracleParameter Parameter {
get {
return _parameter;
}
}
internal void Bind (OciStatementHandle statementHandle, NativeBuffer parameterBuffer, OracleConnection connection, ref bool mustRelease, ref SafeHandle handleToBind) {
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: You must have called DangerousAddRef on the parameterBuffer
// before calling this method, or you run the risk of allowing
// Handle Recycling to occur!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
IntPtr h;
// Don't bother with parameters where the user asks for the default value.
if ( !IsDirection(Parameter, ParameterDirection.Output) && null == Parameter.Value) {
return;
}
string parameterName = Parameter.ParameterName;
OciErrorHandle errorHandle = connection.ErrorHandle;
OciServiceContextHandle serviceContextHandle = connection.ServiceContextHandle;
int valueLength = 0; // number of BYTES written to the valueLocation for the INPUT value.
int bufferLength; // number of BYTES we tell Oracle that we have provided space for in our buffer (may be shorter than actual buffer)
OCI.INDICATOR indicatorValue = OCI.INDICATOR.OK;
OCI.DATATYPE ociType = _bindingMetaType.OciType;
IntPtr indicatorLocation = parameterBuffer.DangerousGetDataPtr(_indicatorOffset);
IntPtr lengthLocation = parameterBuffer.DangerousGetDataPtr(_lengthOffset);
IntPtr valueLocation = parameterBuffer.DangerousGetDataPtr(_valueOffset);
OciHandle.SafeDispose(ref _dateTimeDescriptor);
// First, write the value to the parameter buffer and get the number
// of bytes written.
if (IsDirection(Parameter, ParameterDirection.Input)) {
if (ADP.IsNull(_coercedValue)) {
indicatorValue = OCI.INDICATOR.ISNULL;
// for TIMESTAMP types, we still have to provide the descriptor, even if the value is null
switch (ociType)
{
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
_dateTimeDescriptor = OracleDateTime.CreateEmptyDescriptor(ociType, connection);
handleToBind = _dateTimeDescriptor;
break;
}
}
else {
valueLength = PutOracleValue(
_coercedValue,
parameterBuffer,
_valueOffset,
_bindingMetaType,
connection,
ref handleToBind);
}
}
else {
Debug.Assert(IsDirection(Parameter, ParameterDirection.Output), "non-output output parameter?");
if (_bindingMetaType.IsVariableLength)
valueLength = 0; // Output-only values never have an input length...
else
valueLength = _bufferLength; // ...except when they're fixed length, to avoid ORA-01459 errors
OciLobLocator.SafeDispose(ref _locator);
OciHandle.SafeDispose(ref _descriptor);
switch (ociType) {
case OCI.DATATYPE.BFILE:
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
_locator = new OciLobLocator(connection, _bindingMetaType.OracleType);
handleToBind = _locator.Descriptor;
break;
case OCI.DATATYPE.RSET:
_descriptor = new OciStatementHandle(serviceContextHandle);
handleToBind = _descriptor;
break;
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
_dateTimeDescriptor = OracleDateTime.CreateEmptyDescriptor(ociType, connection);
handleToBind = _dateTimeDescriptor;
break;
}
}
// We need to add-ref the handle so it can't be released somehow
// by another thread while we're executing. Only after we do that
// can we write it to the buffer for the Oracle to use during the
// Execute. The caller is required to provide storage for the
// handleToBind and ensure that the DangerousRelease is called
// in it's CER.
if (null != handleToBind) {
handleToBind.DangerousAddRef(ref mustRelease);
parameterBuffer.WriteIntPtr(_valueOffset, handleToBind.DangerousGetHandle());
}
// Second, write the indicatorValue (whether the parameter has a null
// value or not) to the parameter buffer.
parameterBuffer.WriteInt16(_indicatorOffset, (Int16)indicatorValue);
// Third, write the length of the input value to the parameter buffer.
//
// Don't bind a length value for LONGVARCHAR or LONGVARRAW data, or you'll end
// up with ORA-01098: program Interface error during Long Insert\nORA-01458: invalid length inside variable character string
// errors.
if (OCI.DATATYPE.LONGVARCHAR == ociType || OCI.DATATYPE.LONGVARRAW == ociType) {
lengthLocation = IntPtr.Zero;
}
else {
// When we're binding this parameter as UCS2, the length we specify
// must be in characters, not in bytes.
if (_bindAsUCS2)
parameterBuffer.WriteInt32(_lengthOffset, (Int32)(valueLength/ADP.CharSize));
else
parameterBuffer.WriteInt32(_lengthOffset, (Int32)valueLength);
}
// Fourth, compute the number of bytes in the parameter buffer that we need
// to report to Oracle, depending on whether it is an input-only or any type
// of output parameter. For input-only parameters, we only need to report
// the actual value's size, but for output parameters, we have to report the
// full buffer size to avoid truncation of data, should the output value
// exceed the length of the input value.
if (IsDirection(Parameter, ParameterDirection.Output))
bufferLength = _bufferLength;
else
bufferLength = valueLength;
// bind type is different for INT_TIMESTAMP* since we bind them as Oracle's public TIMESTAMP* ones and use descriptors
OCI.DATATYPE bindAsOciType = ociType;
switch (ociType) {
case OCI.DATATYPE.INT_TIMESTAMP:
bindAsOciType = OCI.DATATYPE.TIMESTAMP;
break;
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
bindAsOciType = OCI.DATATYPE.TIMESTAMP_TZ;
break;
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
bindAsOciType = OCI.DATATYPE.TIMESTAMP_LTZ;
break;
}
// Finally, tell Oracle about our parameter.
int rc = TracedNativeMethods.OCIBindByName(
statementHandle,
out h,
errorHandle,
parameterName,
parameterName.Length,
valueLocation,
bufferLength,
bindAsOciType,
indicatorLocation,
lengthLocation,
OCI.MODE.OCI_DEFAULT
);
if (rc != 0)
_command.Connection.CheckError(errorHandle, rc);
_bindHandle = new OciBindHandle(statementHandle, h);
#if TRACEPARAMETERVALUES
if (null != _coercedValue) {
SafeNativeMethods.OutputDebugStringW("Value = '" + _coercedValue.ToString() + "'\n");
}
#endif //TRACEPARAMETERVALUES
// OK, character bindings have a few extra things we need to do to
// deal with character sizes and alternate character sets.
if (_bindingMetaType.IsCharacterType) {
// To avoid problems when our buffer is larger than the maximum number
// of characters, we use OCI_ATTR_MAXCHAR_SIZE to limit the number of
// characters that will be used. (Except on Oracle8i clients where it
// isn't available)
if (OCI.ClientVersionAtLeastOracle9i
&& IsDirection(Parameter, ParameterDirection.Output))
_bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_MAXCHAR_SIZE, (int)_bindSize, errorHandle);
if ((bufferLength > _bindingMetaType.MaxBindSize / ADP.CharSize)
|| (!OCI.ClientVersionAtLeastOracle9i && _bindingMetaType.UsesNationalCharacterSet)) // need to specify MAXDATA_SIZE for OCI8 UCS2 bindings to work
_bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_MAXDATA_SIZE, (int)_bindingMetaType.MaxBindSize, errorHandle);
// NOTE: the order is important here; setting charsetForm will
// reset charsetId (I found this out the hard way...)
if (_bindingMetaType.UsesNationalCharacterSet)
_bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, (int)OCI.CHARSETFORM.SQLCS_NCHAR, errorHandle);
// NOTE: the order is important here; setting charsetForm will
// reset charsetId (I found this out the hard way...)
if (_bindAsUCS2)
_bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_ID, (int)OCI.CHARSETID.OCI_UTF16ID, errorHandle);
}
GC.KeepAlive(parameterBuffer);
}
private OracleLob CreateTemporaryLobForValue(OracleConnection connection, OracleType oracleType, object value) {
switch (oracleType) {
case OracleType.BFile:
// Note that we can't really construct a temporary BFILE, so we
// construct a BLOB instead. This is safe because Oracle won't
// let you write to a BFILE, so the caller is using it as an Input
// parameter.
oracleType = OracleType.Blob;
break;
case OracleType.Blob:
case OracleType.Clob:
case OracleType.NClob:
break;
default:
throw ADP.InvalidLobType(oracleType);
}
OracleLob tempLob = new OracleLob(connection, oracleType);
byte[] byteArrayValue = value as byte[];
if (null != byteArrayValue) {
tempLob.Write(byteArrayValue,0,byteArrayValue.Length);
}
else {
System.Text.Encoding UnicodeWithoutBOMs = new System.Text.UnicodeEncoding(false, false); // Oracle won't put in BOMs, so neither should we...
tempLob.Seek(0,SeekOrigin.Begin);
StreamWriter sw = new StreamWriter(tempLob, UnicodeWithoutBOMs);
sw.Write(value);
sw.Flush();
}
return tempLob;
}
internal object GetOutputValue(
NativeBuffer parameterBuffer,
OracleConnection connection, // connection, so we can create LOB values
bool needCLSType
) {
object result;
// Returns an object that contains the value of the column in the
// specified row buffer. This method returns Oracle-typed objects.
if (parameterBuffer.ReadInt16(_indicatorOffset) == (Int16)OCI.INDICATOR.ISNULL)
return DBNull.Value;
switch (_bindingMetaType.OciType) {
case OCI.DATATYPE.FLOAT:
case OCI.DATATYPE.INTEGER:
case OCI.DATATYPE.UNSIGNEDINT:
result = parameterBuffer.PtrToStructure(_valueOffset, _bindingMetaType.BaseType);
return result;
case OCI.DATATYPE.BFILE:
result = new OracleBFile(_locator);
return result;
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW:
case OCI.DATATYPE.LONGVARRAW:
result = new OracleBinary(parameterBuffer, _valueOffset, _lengthOffset, _bindingMetaType);
if (needCLSType) {
object newresult = ((OracleBinary)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.RSET:
result = new OracleDataReader(connection, _descriptor);
return result;
case OCI.DATATYPE.DATE:
result = new OracleDateTime(parameterBuffer, _valueOffset, _lengthOffset, _bindingMetaType, connection);
if (needCLSType) {
object newresult = ((OracleDateTime)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
result = new OracleDateTime(_dateTimeDescriptor, _bindingMetaType, connection);
if (needCLSType) {
object newresult = ((OracleDateTime)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
result = new OracleLob(_locator);
return result;
case OCI.DATATYPE.INT_INTERVAL_YM:
result = new OracleMonthSpan(parameterBuffer, _valueOffset);
if (needCLSType) {
object newresult = ((OracleMonthSpan)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.VARNUM:
result = new OracleNumber(parameterBuffer, _valueOffset);
if (needCLSType) {
object newresult = ((OracleNumber)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
case OCI.DATATYPE.LONG:
case OCI.DATATYPE.LONGVARCHAR:
result = new OracleString(parameterBuffer,
_valueOffset,
_lengthOffset,
_bindingMetaType,
connection,
_bindAsUCS2,
true
);
int size = _parameter.Size;
if (0 != size && size < ((OracleString)result).Length) {
string truncatedResult = ((OracleString)result).Value.Substring(0,size);
if (needCLSType)
result = truncatedResult;
else
result = new OracleString(truncatedResult);
}
else if (needCLSType) {
object newresult = ((OracleString)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.INT_INTERVAL_DS:
result = new OracleTimeSpan(parameterBuffer, _valueOffset);
if (needCLSType) {
object newresult = ((OracleTimeSpan)result).Value;
result = newresult;
}
return result;
}
throw ADP.TypeNotSupported(_bindingMetaType.OciType);
}
internal void Dispose() {
OciHandle.SafeDispose(ref _bindHandle);
// Make sure we clean up any temporary lob we may have constructed
// so they don't leak.
if (_freeTemporaryLob) {
OracleLob temporaryLob = _coercedValue as OracleLob;
if (null != temporaryLob) {
temporaryLob.Free();
}
}
}
static internal bool IsDirection(IDataParameter value, ParameterDirection condition) {
return (condition == (condition & value.Direction));
}
private bool IsEmpty(object value) {
bool result = false;
if (value is string) {
result = (0 == ((string) value).Length);
}
if (value is OracleString) {
result = (0 == ((OracleString) value).Length);
}
if (value is char[]) {
result = (0 == ((char[]) value).Length);
}
if (value is byte[]) {
result = (0 == ((byte[]) value).Length);
}
if (value is OracleBinary) {
result = (0 == ((OracleBinary) value).Length);
}
return result;
}
internal void PostExecute (NativeBuffer parameterBuffer, OracleConnection connection) { // connection, so we can create LOB values
OracleParameter parameter = Parameter;
if (IsDirection(parameter, ParameterDirection.Output)
|| IsDirection(parameter, ParameterDirection.ReturnValue)) {
bool needCLSType = true;
if (IsDirection(parameter, ParameterDirection.Input)) {
object inputValue = parameter.Value;
if (inputValue is INullable) {
needCLSType = false;
}
}
parameter.Value = GetOutputValue(parameterBuffer, connection, needCLSType);
}
}
internal void PrepareForBind (OracleConnection connection, ref int offset) {
OracleParameter parameter = Parameter;
bool useLONGBinding = false;
object value = parameter.Value;
// Don't bother with parameters where the user asks for the default value.
if ( !IsDirection(parameter, ParameterDirection.Output) && (null == value)) {
_bufferLength = 0;
return;
}
_bindingMetaType = parameter.GetMetaType(value);
// We currently don't support binding a REF CURSOR as an input
// parameter; that is for a future release.
if (OCI.DATATYPE.RSET == _bindingMetaType.OciType && ADP.IsDirection(parameter.Direction, ParameterDirection.Input))
throw ADP.InputRefCursorNotSupported(parameter.ParameterName);
// Make sure we have a coerced value, if we haven't already done
// so, then save it.
parameter.SetCoercedValueInternal(value, _bindingMetaType);
_coercedValue = parameter.GetCoercedValueInternal();
// WebData 103336 - When the customer requests that we use a LOB we
// need to use a LOB, so that it can be processed by PL/SQL, which
// can't handle values larger than 32000 bytes. When they don't pass
// us a LOB or a BFILE as the value, we silently construct a
// temporary LOB for them. This is necessary for DataAdapter.Update.
switch (_bindingMetaType.OciType) {
case OCI.DATATYPE.BFILE:
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
if (!ADP.IsNull(_coercedValue) && !(_coercedValue is OracleLob || _coercedValue is OracleBFile)) {
// WebData 104205 - Except I forgot that you have to be in a
// transaction to write to a LOB. Since we don't want to break
// people that currently work outside of a transaction, we
// need to limit when we use temporary LOBs to when we already
// have a transaction. Other than that, they're out of luck.
if (connection.HasTransaction) {
_freeTemporaryLob = true;
_coercedValue = CreateTemporaryLobForValue(connection, _bindingMetaType.OracleType, _coercedValue);
}
else {
_bindingMetaType = MetaType.GetMetaTypeForType(_bindingMetaType.DbType);
useLONGBinding = true;
}
}
break;
}
// For fixed-width types, we take the bind size from the meta type
// information; if it's zero, then the type must be variable width
// (or it's an output parameter) and we require that they specify a
// size.
_bindSize = _bindingMetaType.BindSize;
if ((IsDirection(parameter, ParameterDirection.Output)
&& _bindingMetaType.IsVariableLength) // they must specify a size for variable-length output parameters...
|| (0 == _bindSize && !ADP.IsNull(_coercedValue)) // ...or if it's a non-null, variable-length input paramter...
|| (_bindSize > short.MaxValue) ) { // ...or if the parameter type's maximum size is huge.
int size = parameter.BindSize;
if (0 != size)
_bindSize = size;
if ((0 == _bindSize || MetaType.LongMax == _bindSize) && !IsEmpty(_coercedValue))
throw ADP.ParameterSizeIsMissing(parameter.ParameterName, _bindingMetaType.BaseType);
}
// Now determine the number of bytes we require in the buffer. For
// character types, we must adjust for the size of the characters that
// we will bind.
_bufferLength = _bindSize;
if (_bindingMetaType.IsCharacterType && connection.ServerVersionAtLeastOracle8) {
_bindAsUCS2 = true;
_bufferLength *= ADP.CharSize;
}
// Anything with a length that exceeds what fits into a two-byte integer
// requires special binding because the base types don't allow more than
// 65535 bytes. We change the binding under the covers to reflect the
// different type.
if (!ADP.IsNull(_coercedValue) && (_bindSize > _bindingMetaType.MaxBindSize || useLONGBinding)) {
// DEVNOTE: it is perfectly fine to bind values less than 65535 bytes
// as long, so there's no problem with using the maximum number
// of bytes for each Unicode character above.
switch (_bindingMetaType.OciType) {
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.LONG:
case OCI.DATATYPE.VARCHAR2:
_bindingMetaType = (_bindingMetaType.UsesNationalCharacterSet )
? MetaType.oracleTypeMetaType_LONGNVARCHAR
: MetaType.oracleTypeMetaType_LONGVARCHAR;
break;
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW:
_bindingMetaType = MetaType.oracleTypeMetaType_LONGVARRAW;
break;
default:
Debug.Assert(false, "invalid type for long binding!"); // this should never happen!
break;
}
// Long data requires a LONGVARCHAR or LONGVARRAW binding instead, which
// mean we have to add another 4 bytes for the length.
_bufferLength += 4;
}
if (0 > _bufferLength)
throw ADP.ParameterSizeIsTooLarge(parameter.ParameterName);
_indicatorOffset = offset; offset += IntPtr.Size;
_lengthOffset = offset; offset += IntPtr.Size;
_valueOffset = offset; offset += _bufferLength;
offset = (offset + (IntPtr.Size-1)) & ~(IntPtr.Size-1); // align buffer;
}
internal int PutOracleValue( object value, NativeBuffer buffer, int bufferOffset, MetaType metaType, OracleConnection connection, ref SafeHandle handleToBind) {
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: You must have called DangerousAddRef on the buffer
// before calling this method, or you run the risk of allowing
// Handle Recycling to occur!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// writes the managed object into the buffer in the appropriate
// native Oracle format.
handleToBind = null;
OCI.DATATYPE ociType = metaType.OciType;
int dataSize;
OracleParameter parameter = Parameter;
switch (ociType) {
case OCI.DATATYPE.FLOAT:
case OCI.DATATYPE.INTEGER:
case OCI.DATATYPE.UNSIGNEDINT:
buffer.StructureToPtr(bufferOffset, value);
dataSize = metaType.BindSize;
break;
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW:
case OCI.DATATYPE.LONGVARRAW:
{
byte[] from;
if (_coercedValue is OracleBinary) {
OracleBinary temp = (OracleBinary)_coercedValue;
from = temp.Value;
}
else {
from = (byte[])_coercedValue;
}
int ociBytes = from.Length - parameter.Offset;
int size = parameter.GetActualSize();
if (0 != size) {
ociBytes = Math.Min(ociBytes, size);
}
if ( OCI.DATATYPE.LONGVARRAW == ociType ) {
buffer.WriteInt32(bufferOffset, ociBytes);
bufferOffset = checked((int)bufferOffset + 4) ;
dataSize = ociBytes + 4;
}
else {
Debug.Assert (short.MaxValue >= ociBytes, "invalid size for non-LONG data?");
dataSize = ociBytes ;
}
buffer.WriteBytes(bufferOffset, from, parameter.Offset, ociBytes);
}
break;
case OCI.DATATYPE.DATE:
dataSize = OracleDateTime.MarshalDateToNative(value, buffer, bufferOffset, ociType, connection);
break;
// SQLBUVSTS 223628 New code doesn't handle TimestampWithTZ correctly for OracleDateTime. Reverting
// to RTM behavior of throwing an exception for this combination.
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
if (value is OracleDateTime && !((OracleDateTime)value).HasTimeZoneInfo) {
// VSTS 223628: for 2.0 RTM compatibility, raise ArgumentOutOfRangeException if
// the input value size is less than the bound type size
throw ADP.UnsupportedOracleDateTimeBinding(OracleType.TimestampWithTZ);
}
_dateTimeDescriptor = OracleDateTime.CreateDescriptor(ociType, connection, value);
handleToBind = _dateTimeDescriptor;
dataSize = IntPtr.Size;
break;
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
if (value is OracleDateTime && !((OracleDateTime)value).HasTimeInfo) {
// VSTS 223628: for 2.0 RTM compatibility, raise ArgumentOutOfRangeException if
// the input value size is less than the bound type size
throw ADP.UnsupportedOracleDateTimeBinding(metaType.OracleType);
}
_dateTimeDescriptor = OracleDateTime.CreateDescriptor(ociType, connection, value);
handleToBind = _dateTimeDescriptor;
dataSize = IntPtr.Size;
break;
case OCI.DATATYPE.BFILE:
// We cannot construct lobs; if you want to bind a lob, you have to have
// a lob.
if ( !(value is OracleBFile) )
throw ADP.BadBindValueType(value.GetType(), metaType.OracleType);
handleToBind = ((OracleBFile) value).Descriptor;
dataSize = IntPtr.Size;
break;
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
// We cannot construct lobs; if you want to bind a lob, you have to have
// a lob.
if ( !(value is OracleLob) )
throw ADP.BadBindValueType(value.GetType(), metaType.OracleType);
handleToBind = ((OracleLob) value).Descriptor;
dataSize = IntPtr.Size;
break;
case OCI.DATATYPE.INT_INTERVAL_YM:
dataSize = OracleMonthSpan.MarshalToNative(value, buffer, bufferOffset);
break;
case OCI.DATATYPE.VARNUM:
dataSize = OracleNumber.MarshalToNative(value, buffer, bufferOffset, connection);
break;
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
case OCI.DATATYPE.LONG:
case OCI.DATATYPE.LONGVARCHAR:
dataSize = OracleString.MarshalToNative(value, parameter.Offset, parameter.GetActualSize(), buffer, bufferOffset, ociType, _bindAsUCS2);
break;
case OCI.DATATYPE.INT_INTERVAL_DS:
dataSize = OracleTimeSpan.MarshalToNative(value, buffer, bufferOffset);
break;
default:
throw ADP.TypeNotSupported(ociType);
}
Debug.Assert(dataSize <= _bufferLength, String.Format((IFormatProvider)null, "Internal Error: Exceeded Internal Buffer. DataSize={0} BufferLength={1}",dataSize,_bufferLength));
return dataSize;
}
}
};
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// [....]
//-----------------------------------------------------------------------------
namespace System.Data.OracleClient
{
using System;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
//---------------------------------------------------------------------
// OracleParameterBinding
//
// this class is meant to handle the parameter binding for an
// single command object (since parameters can be bound concurrently
// to multiple command objects)
//
sealed internal class OracleParameterBinding {
OracleCommand _command; // the command that this binding is for
OracleParameter _parameter; // the parameter that this binding is for
object _coercedValue; // _parameter.CoercedValue;
MetaType _bindingMetaType; // meta type of the binding, in case it needs adjustment (String bound as CLOB, etc...)
OciBindHandle _bindHandle; // the bind handle, once this has been bound
int _bindSize; // number of bytes/characters to reserve on the server
int _bufferLength; // number of bytes required to bind the value
int _indicatorOffset; // offset from the start of the parameter buffer to the indicator binding (see OCI.INDICATOR)
int _lengthOffset; // offset from the start of the parameter buffer to the length binding
int _valueOffset; // offset from the start of the parameter buffer to the value binding
bool _bindAsUCS2; // true when we should bind this as UCS2
bool _freeTemporaryLob; // true when we've allocated a temporary lob (in _coercedValue) that must be freed.
OciStatementHandle _descriptor; // ref cursor handle for ref cursor types.
OciLobLocator _locator; // lob locator for BFile and Lob types.
OciDateTimeDescriptor _dateTimeDescriptor; // OCI datetime descriptor to hold date time values
// Construct an "empty" parameter
internal OracleParameterBinding (OracleCommand command, OracleParameter parameter) {
_command = command;
_parameter = parameter;
}
internal OracleParameter Parameter {
get {
return _parameter;
}
}
internal void Bind (OciStatementHandle statementHandle, NativeBuffer parameterBuffer, OracleConnection connection, ref bool mustRelease, ref SafeHandle handleToBind) {
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: You must have called DangerousAddRef on the parameterBuffer
// before calling this method, or you run the risk of allowing
// Handle Recycling to occur!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
IntPtr h;
// Don't bother with parameters where the user asks for the default value.
if ( !IsDirection(Parameter, ParameterDirection.Output) && null == Parameter.Value) {
return;
}
string parameterName = Parameter.ParameterName;
OciErrorHandle errorHandle = connection.ErrorHandle;
OciServiceContextHandle serviceContextHandle = connection.ServiceContextHandle;
int valueLength = 0; // number of BYTES written to the valueLocation for the INPUT value.
int bufferLength; // number of BYTES we tell Oracle that we have provided space for in our buffer (may be shorter than actual buffer)
OCI.INDICATOR indicatorValue = OCI.INDICATOR.OK;
OCI.DATATYPE ociType = _bindingMetaType.OciType;
IntPtr indicatorLocation = parameterBuffer.DangerousGetDataPtr(_indicatorOffset);
IntPtr lengthLocation = parameterBuffer.DangerousGetDataPtr(_lengthOffset);
IntPtr valueLocation = parameterBuffer.DangerousGetDataPtr(_valueOffset);
OciHandle.SafeDispose(ref _dateTimeDescriptor);
// First, write the value to the parameter buffer and get the number
// of bytes written.
if (IsDirection(Parameter, ParameterDirection.Input)) {
if (ADP.IsNull(_coercedValue)) {
indicatorValue = OCI.INDICATOR.ISNULL;
// for TIMESTAMP types, we still have to provide the descriptor, even if the value is null
switch (ociType)
{
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
_dateTimeDescriptor = OracleDateTime.CreateEmptyDescriptor(ociType, connection);
handleToBind = _dateTimeDescriptor;
break;
}
}
else {
valueLength = PutOracleValue(
_coercedValue,
parameterBuffer,
_valueOffset,
_bindingMetaType,
connection,
ref handleToBind);
}
}
else {
Debug.Assert(IsDirection(Parameter, ParameterDirection.Output), "non-output output parameter?");
if (_bindingMetaType.IsVariableLength)
valueLength = 0; // Output-only values never have an input length...
else
valueLength = _bufferLength; // ...except when they're fixed length, to avoid ORA-01459 errors
OciLobLocator.SafeDispose(ref _locator);
OciHandle.SafeDispose(ref _descriptor);
switch (ociType) {
case OCI.DATATYPE.BFILE:
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
_locator = new OciLobLocator(connection, _bindingMetaType.OracleType);
handleToBind = _locator.Descriptor;
break;
case OCI.DATATYPE.RSET:
_descriptor = new OciStatementHandle(serviceContextHandle);
handleToBind = _descriptor;
break;
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
_dateTimeDescriptor = OracleDateTime.CreateEmptyDescriptor(ociType, connection);
handleToBind = _dateTimeDescriptor;
break;
}
}
// We need to add-ref the handle so it can't be released somehow
// by another thread while we're executing. Only after we do that
// can we write it to the buffer for the Oracle to use during the
// Execute. The caller is required to provide storage for the
// handleToBind and ensure that the DangerousRelease is called
// in it's CER.
if (null != handleToBind) {
handleToBind.DangerousAddRef(ref mustRelease);
parameterBuffer.WriteIntPtr(_valueOffset, handleToBind.DangerousGetHandle());
}
// Second, write the indicatorValue (whether the parameter has a null
// value or not) to the parameter buffer.
parameterBuffer.WriteInt16(_indicatorOffset, (Int16)indicatorValue);
// Third, write the length of the input value to the parameter buffer.
//
// Don't bind a length value for LONGVARCHAR or LONGVARRAW data, or you'll end
// up with ORA-01098: program Interface error during Long Insert\nORA-01458: invalid length inside variable character string
// errors.
if (OCI.DATATYPE.LONGVARCHAR == ociType || OCI.DATATYPE.LONGVARRAW == ociType) {
lengthLocation = IntPtr.Zero;
}
else {
// When we're binding this parameter as UCS2, the length we specify
// must be in characters, not in bytes.
if (_bindAsUCS2)
parameterBuffer.WriteInt32(_lengthOffset, (Int32)(valueLength/ADP.CharSize));
else
parameterBuffer.WriteInt32(_lengthOffset, (Int32)valueLength);
}
// Fourth, compute the number of bytes in the parameter buffer that we need
// to report to Oracle, depending on whether it is an input-only or any type
// of output parameter. For input-only parameters, we only need to report
// the actual value's size, but for output parameters, we have to report the
// full buffer size to avoid truncation of data, should the output value
// exceed the length of the input value.
if (IsDirection(Parameter, ParameterDirection.Output))
bufferLength = _bufferLength;
else
bufferLength = valueLength;
// bind type is different for INT_TIMESTAMP* since we bind them as Oracle's public TIMESTAMP* ones and use descriptors
OCI.DATATYPE bindAsOciType = ociType;
switch (ociType) {
case OCI.DATATYPE.INT_TIMESTAMP:
bindAsOciType = OCI.DATATYPE.TIMESTAMP;
break;
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
bindAsOciType = OCI.DATATYPE.TIMESTAMP_TZ;
break;
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
bindAsOciType = OCI.DATATYPE.TIMESTAMP_LTZ;
break;
}
// Finally, tell Oracle about our parameter.
int rc = TracedNativeMethods.OCIBindByName(
statementHandle,
out h,
errorHandle,
parameterName,
parameterName.Length,
valueLocation,
bufferLength,
bindAsOciType,
indicatorLocation,
lengthLocation,
OCI.MODE.OCI_DEFAULT
);
if (rc != 0)
_command.Connection.CheckError(errorHandle, rc);
_bindHandle = new OciBindHandle(statementHandle, h);
#if TRACEPARAMETERVALUES
if (null != _coercedValue) {
SafeNativeMethods.OutputDebugStringW("Value = '" + _coercedValue.ToString() + "'\n");
}
#endif //TRACEPARAMETERVALUES
// OK, character bindings have a few extra things we need to do to
// deal with character sizes and alternate character sets.
if (_bindingMetaType.IsCharacterType) {
// To avoid problems when our buffer is larger than the maximum number
// of characters, we use OCI_ATTR_MAXCHAR_SIZE to limit the number of
// characters that will be used. (Except on Oracle8i clients where it
// isn't available)
if (OCI.ClientVersionAtLeastOracle9i
&& IsDirection(Parameter, ParameterDirection.Output))
_bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_MAXCHAR_SIZE, (int)_bindSize, errorHandle);
if ((bufferLength > _bindingMetaType.MaxBindSize / ADP.CharSize)
|| (!OCI.ClientVersionAtLeastOracle9i && _bindingMetaType.UsesNationalCharacterSet)) // need to specify MAXDATA_SIZE for OCI8 UCS2 bindings to work
_bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_MAXDATA_SIZE, (int)_bindingMetaType.MaxBindSize, errorHandle);
// NOTE: the order is important here; setting charsetForm will
// reset charsetId (I found this out the hard way...)
if (_bindingMetaType.UsesNationalCharacterSet)
_bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, (int)OCI.CHARSETFORM.SQLCS_NCHAR, errorHandle);
// NOTE: the order is important here; setting charsetForm will
// reset charsetId (I found this out the hard way...)
if (_bindAsUCS2)
_bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_ID, (int)OCI.CHARSETID.OCI_UTF16ID, errorHandle);
}
GC.KeepAlive(parameterBuffer);
}
private OracleLob CreateTemporaryLobForValue(OracleConnection connection, OracleType oracleType, object value) {
switch (oracleType) {
case OracleType.BFile:
// Note that we can't really construct a temporary BFILE, so we
// construct a BLOB instead. This is safe because Oracle won't
// let you write to a BFILE, so the caller is using it as an Input
// parameter.
oracleType = OracleType.Blob;
break;
case OracleType.Blob:
case OracleType.Clob:
case OracleType.NClob:
break;
default:
throw ADP.InvalidLobType(oracleType);
}
OracleLob tempLob = new OracleLob(connection, oracleType);
byte[] byteArrayValue = value as byte[];
if (null != byteArrayValue) {
tempLob.Write(byteArrayValue,0,byteArrayValue.Length);
}
else {
System.Text.Encoding UnicodeWithoutBOMs = new System.Text.UnicodeEncoding(false, false); // Oracle won't put in BOMs, so neither should we...
tempLob.Seek(0,SeekOrigin.Begin);
StreamWriter sw = new StreamWriter(tempLob, UnicodeWithoutBOMs);
sw.Write(value);
sw.Flush();
}
return tempLob;
}
internal object GetOutputValue(
NativeBuffer parameterBuffer,
OracleConnection connection, // connection, so we can create LOB values
bool needCLSType
) {
object result;
// Returns an object that contains the value of the column in the
// specified row buffer. This method returns Oracle-typed objects.
if (parameterBuffer.ReadInt16(_indicatorOffset) == (Int16)OCI.INDICATOR.ISNULL)
return DBNull.Value;
switch (_bindingMetaType.OciType) {
case OCI.DATATYPE.FLOAT:
case OCI.DATATYPE.INTEGER:
case OCI.DATATYPE.UNSIGNEDINT:
result = parameterBuffer.PtrToStructure(_valueOffset, _bindingMetaType.BaseType);
return result;
case OCI.DATATYPE.BFILE:
result = new OracleBFile(_locator);
return result;
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW:
case OCI.DATATYPE.LONGVARRAW:
result = new OracleBinary(parameterBuffer, _valueOffset, _lengthOffset, _bindingMetaType);
if (needCLSType) {
object newresult = ((OracleBinary)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.RSET:
result = new OracleDataReader(connection, _descriptor);
return result;
case OCI.DATATYPE.DATE:
result = new OracleDateTime(parameterBuffer, _valueOffset, _lengthOffset, _bindingMetaType, connection);
if (needCLSType) {
object newresult = ((OracleDateTime)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
result = new OracleDateTime(_dateTimeDescriptor, _bindingMetaType, connection);
if (needCLSType) {
object newresult = ((OracleDateTime)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
result = new OracleLob(_locator);
return result;
case OCI.DATATYPE.INT_INTERVAL_YM:
result = new OracleMonthSpan(parameterBuffer, _valueOffset);
if (needCLSType) {
object newresult = ((OracleMonthSpan)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.VARNUM:
result = new OracleNumber(parameterBuffer, _valueOffset);
if (needCLSType) {
object newresult = ((OracleNumber)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
case OCI.DATATYPE.LONG:
case OCI.DATATYPE.LONGVARCHAR:
result = new OracleString(parameterBuffer,
_valueOffset,
_lengthOffset,
_bindingMetaType,
connection,
_bindAsUCS2,
true
);
int size = _parameter.Size;
if (0 != size && size < ((OracleString)result).Length) {
string truncatedResult = ((OracleString)result).Value.Substring(0,size);
if (needCLSType)
result = truncatedResult;
else
result = new OracleString(truncatedResult);
}
else if (needCLSType) {
object newresult = ((OracleString)result).Value;
result = newresult;
}
return result;
case OCI.DATATYPE.INT_INTERVAL_DS:
result = new OracleTimeSpan(parameterBuffer, _valueOffset);
if (needCLSType) {
object newresult = ((OracleTimeSpan)result).Value;
result = newresult;
}
return result;
}
throw ADP.TypeNotSupported(_bindingMetaType.OciType);
}
internal void Dispose() {
OciHandle.SafeDispose(ref _bindHandle);
// Make sure we clean up any temporary lob we may have constructed
// so they don't leak.
if (_freeTemporaryLob) {
OracleLob temporaryLob = _coercedValue as OracleLob;
if (null != temporaryLob) {
temporaryLob.Free();
}
}
}
static internal bool IsDirection(IDataParameter value, ParameterDirection condition) {
return (condition == (condition & value.Direction));
}
private bool IsEmpty(object value) {
bool result = false;
if (value is string) {
result = (0 == ((string) value).Length);
}
if (value is OracleString) {
result = (0 == ((OracleString) value).Length);
}
if (value is char[]) {
result = (0 == ((char[]) value).Length);
}
if (value is byte[]) {
result = (0 == ((byte[]) value).Length);
}
if (value is OracleBinary) {
result = (0 == ((OracleBinary) value).Length);
}
return result;
}
internal void PostExecute (NativeBuffer parameterBuffer, OracleConnection connection) { // connection, so we can create LOB values
OracleParameter parameter = Parameter;
if (IsDirection(parameter, ParameterDirection.Output)
|| IsDirection(parameter, ParameterDirection.ReturnValue)) {
bool needCLSType = true;
if (IsDirection(parameter, ParameterDirection.Input)) {
object inputValue = parameter.Value;
if (inputValue is INullable) {
needCLSType = false;
}
}
parameter.Value = GetOutputValue(parameterBuffer, connection, needCLSType);
}
}
internal void PrepareForBind (OracleConnection connection, ref int offset) {
OracleParameter parameter = Parameter;
bool useLONGBinding = false;
object value = parameter.Value;
// Don't bother with parameters where the user asks for the default value.
if ( !IsDirection(parameter, ParameterDirection.Output) && (null == value)) {
_bufferLength = 0;
return;
}
_bindingMetaType = parameter.GetMetaType(value);
// We currently don't support binding a REF CURSOR as an input
// parameter; that is for a future release.
if (OCI.DATATYPE.RSET == _bindingMetaType.OciType && ADP.IsDirection(parameter.Direction, ParameterDirection.Input))
throw ADP.InputRefCursorNotSupported(parameter.ParameterName);
// Make sure we have a coerced value, if we haven't already done
// so, then save it.
parameter.SetCoercedValueInternal(value, _bindingMetaType);
_coercedValue = parameter.GetCoercedValueInternal();
// WebData 103336 - When the customer requests that we use a LOB we
// need to use a LOB, so that it can be processed by PL/SQL, which
// can't handle values larger than 32000 bytes. When they don't pass
// us a LOB or a BFILE as the value, we silently construct a
// temporary LOB for them. This is necessary for DataAdapter.Update.
switch (_bindingMetaType.OciType) {
case OCI.DATATYPE.BFILE:
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
if (!ADP.IsNull(_coercedValue) && !(_coercedValue is OracleLob || _coercedValue is OracleBFile)) {
// WebData 104205 - Except I forgot that you have to be in a
// transaction to write to a LOB. Since we don't want to break
// people that currently work outside of a transaction, we
// need to limit when we use temporary LOBs to when we already
// have a transaction. Other than that, they're out of luck.
if (connection.HasTransaction) {
_freeTemporaryLob = true;
_coercedValue = CreateTemporaryLobForValue(connection, _bindingMetaType.OracleType, _coercedValue);
}
else {
_bindingMetaType = MetaType.GetMetaTypeForType(_bindingMetaType.DbType);
useLONGBinding = true;
}
}
break;
}
// For fixed-width types, we take the bind size from the meta type
// information; if it's zero, then the type must be variable width
// (or it's an output parameter) and we require that they specify a
// size.
_bindSize = _bindingMetaType.BindSize;
if ((IsDirection(parameter, ParameterDirection.Output)
&& _bindingMetaType.IsVariableLength) // they must specify a size for variable-length output parameters...
|| (0 == _bindSize && !ADP.IsNull(_coercedValue)) // ...or if it's a non-null, variable-length input paramter...
|| (_bindSize > short.MaxValue) ) { // ...or if the parameter type's maximum size is huge.
int size = parameter.BindSize;
if (0 != size)
_bindSize = size;
if ((0 == _bindSize || MetaType.LongMax == _bindSize) && !IsEmpty(_coercedValue))
throw ADP.ParameterSizeIsMissing(parameter.ParameterName, _bindingMetaType.BaseType);
}
// Now determine the number of bytes we require in the buffer. For
// character types, we must adjust for the size of the characters that
// we will bind.
_bufferLength = _bindSize;
if (_bindingMetaType.IsCharacterType && connection.ServerVersionAtLeastOracle8) {
_bindAsUCS2 = true;
_bufferLength *= ADP.CharSize;
}
// Anything with a length that exceeds what fits into a two-byte integer
// requires special binding because the base types don't allow more than
// 65535 bytes. We change the binding under the covers to reflect the
// different type.
if (!ADP.IsNull(_coercedValue) && (_bindSize > _bindingMetaType.MaxBindSize || useLONGBinding)) {
// DEVNOTE: it is perfectly fine to bind values less than 65535 bytes
// as long, so there's no problem with using the maximum number
// of bytes for each Unicode character above.
switch (_bindingMetaType.OciType) {
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.LONG:
case OCI.DATATYPE.VARCHAR2:
_bindingMetaType = (_bindingMetaType.UsesNationalCharacterSet )
? MetaType.oracleTypeMetaType_LONGNVARCHAR
: MetaType.oracleTypeMetaType_LONGVARCHAR;
break;
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW:
_bindingMetaType = MetaType.oracleTypeMetaType_LONGVARRAW;
break;
default:
Debug.Assert(false, "invalid type for long binding!"); // this should never happen!
break;
}
// Long data requires a LONGVARCHAR or LONGVARRAW binding instead, which
// mean we have to add another 4 bytes for the length.
_bufferLength += 4;
}
if (0 > _bufferLength)
throw ADP.ParameterSizeIsTooLarge(parameter.ParameterName);
_indicatorOffset = offset; offset += IntPtr.Size;
_lengthOffset = offset; offset += IntPtr.Size;
_valueOffset = offset; offset += _bufferLength;
offset = (offset + (IntPtr.Size-1)) & ~(IntPtr.Size-1); // align buffer;
}
internal int PutOracleValue( object value, NativeBuffer buffer, int bufferOffset, MetaType metaType, OracleConnection connection, ref SafeHandle handleToBind) {
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: You must have called DangerousAddRef on the buffer
// before calling this method, or you run the risk of allowing
// Handle Recycling to occur!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// writes the managed object into the buffer in the appropriate
// native Oracle format.
handleToBind = null;
OCI.DATATYPE ociType = metaType.OciType;
int dataSize;
OracleParameter parameter = Parameter;
switch (ociType) {
case OCI.DATATYPE.FLOAT:
case OCI.DATATYPE.INTEGER:
case OCI.DATATYPE.UNSIGNEDINT:
buffer.StructureToPtr(bufferOffset, value);
dataSize = metaType.BindSize;
break;
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW:
case OCI.DATATYPE.LONGVARRAW:
{
byte[] from;
if (_coercedValue is OracleBinary) {
OracleBinary temp = (OracleBinary)_coercedValue;
from = temp.Value;
}
else {
from = (byte[])_coercedValue;
}
int ociBytes = from.Length - parameter.Offset;
int size = parameter.GetActualSize();
if (0 != size) {
ociBytes = Math.Min(ociBytes, size);
}
if ( OCI.DATATYPE.LONGVARRAW == ociType ) {
buffer.WriteInt32(bufferOffset, ociBytes);
bufferOffset = checked((int)bufferOffset + 4) ;
dataSize = ociBytes + 4;
}
else {
Debug.Assert (short.MaxValue >= ociBytes, "invalid size for non-LONG data?");
dataSize = ociBytes ;
}
buffer.WriteBytes(bufferOffset, from, parameter.Offset, ociBytes);
}
break;
case OCI.DATATYPE.DATE:
dataSize = OracleDateTime.MarshalDateToNative(value, buffer, bufferOffset, ociType, connection);
break;
// SQLBUVSTS 223628 New code doesn't handle TimestampWithTZ correctly for OracleDateTime. Reverting
// to RTM behavior of throwing an exception for this combination.
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
if (value is OracleDateTime && !((OracleDateTime)value).HasTimeZoneInfo) {
// VSTS 223628: for 2.0 RTM compatibility, raise ArgumentOutOfRangeException if
// the input value size is less than the bound type size
throw ADP.UnsupportedOracleDateTimeBinding(OracleType.TimestampWithTZ);
}
_dateTimeDescriptor = OracleDateTime.CreateDescriptor(ociType, connection, value);
handleToBind = _dateTimeDescriptor;
dataSize = IntPtr.Size;
break;
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
if (value is OracleDateTime && !((OracleDateTime)value).HasTimeInfo) {
// VSTS 223628: for 2.0 RTM compatibility, raise ArgumentOutOfRangeException if
// the input value size is less than the bound type size
throw ADP.UnsupportedOracleDateTimeBinding(metaType.OracleType);
}
_dateTimeDescriptor = OracleDateTime.CreateDescriptor(ociType, connection, value);
handleToBind = _dateTimeDescriptor;
dataSize = IntPtr.Size;
break;
case OCI.DATATYPE.BFILE:
// We cannot construct lobs; if you want to bind a lob, you have to have
// a lob.
if ( !(value is OracleBFile) )
throw ADP.BadBindValueType(value.GetType(), metaType.OracleType);
handleToBind = ((OracleBFile) value).Descriptor;
dataSize = IntPtr.Size;
break;
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
// We cannot construct lobs; if you want to bind a lob, you have to have
// a lob.
if ( !(value is OracleLob) )
throw ADP.BadBindValueType(value.GetType(), metaType.OracleType);
handleToBind = ((OracleLob) value).Descriptor;
dataSize = IntPtr.Size;
break;
case OCI.DATATYPE.INT_INTERVAL_YM:
dataSize = OracleMonthSpan.MarshalToNative(value, buffer, bufferOffset);
break;
case OCI.DATATYPE.VARNUM:
dataSize = OracleNumber.MarshalToNative(value, buffer, bufferOffset, connection);
break;
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
case OCI.DATATYPE.LONG:
case OCI.DATATYPE.LONGVARCHAR:
dataSize = OracleString.MarshalToNative(value, parameter.Offset, parameter.GetActualSize(), buffer, bufferOffset, ociType, _bindAsUCS2);
break;
case OCI.DATATYPE.INT_INTERVAL_DS:
dataSize = OracleTimeSpan.MarshalToNative(value, buffer, bufferOffset);
break;
default:
throw ADP.TypeNotSupported(ociType);
}
Debug.Assert(dataSize <= _bufferLength, String.Format((IFormatProvider)null, "Internal Error: Exceeded Internal Buffer. DataSize={0} BufferLength={1}",dataSize,_bufferLength));
return dataSize;
}
}
};
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HMACSHA512.cs
- httpapplicationstate.cs
- Random.cs
- XmlProcessingInstruction.cs
- PageBreakRecord.cs
- ApplicationInfo.cs
- UserControlBuildProvider.cs
- RegionInfo.cs
- ManifestResourceInfo.cs
- VerbConverter.cs
- ProgressBar.cs
- _RequestCacheProtocol.cs
- ComponentConverter.cs
- BaseTemplateCodeDomTreeGenerator.cs
- StreamWithDictionary.cs
- XmlSchemaSet.cs
- DesignerCategoryAttribute.cs
- PartManifestEntry.cs
- diagnosticsswitches.cs
- RichTextBox.cs
- DesignerUtility.cs
- BitmapFrame.cs
- AttachedPropertyBrowsableForChildrenAttribute.cs
- VersionedStreamOwner.cs
- InfocardExtendedInformationEntry.cs
- CatalogZoneBase.cs
- BindingListCollectionView.cs
- AuthenticationService.cs
- ListViewItem.cs
- ReceiveMessageRecord.cs
- DataGridViewCell.cs
- coordinatorscratchpad.cs
- ImageMap.cs
- BuildProvider.cs
- Point3DCollectionValueSerializer.cs
- WmlObjectListAdapter.cs
- RegexInterpreter.cs
- CursorConverter.cs
- DataGridColumnEventArgs.cs
- WebPartMinimizeVerb.cs
- FileStream.cs
- PointHitTestParameters.cs
- CollectionBase.cs
- Visual3DCollection.cs
- SizeConverter.cs
- GridViewRowEventArgs.cs
- Int32Rect.cs
- UInt16Storage.cs
- Dispatcher.cs
- Screen.cs
- BindingCompleteEventArgs.cs
- userdatakeys.cs
- HtmlToClrEventProxy.cs
- MemberPathMap.cs
- PerformanceCounterTraceRecord.cs
- FixedSOMElement.cs
- CodeCommentStatement.cs
- DataProviderNameConverter.cs
- KeyEvent.cs
- HostedBindingBehavior.cs
- OdbcConnectionString.cs
- SettingsPropertyValueCollection.cs
- MatrixCamera.cs
- DirectionalLight.cs
- TableCell.cs
- WindowsGraphicsWrapper.cs
- Parameter.cs
- _ShellExpression.cs
- AesManaged.cs
- SpotLight.cs
- BCryptSafeHandles.cs
- WebPartEventArgs.cs
- ConfigurationConverterBase.cs
- ObjectListField.cs
- PackageProperties.cs
- TextServicesLoader.cs
- CallContext.cs
- AdornerLayer.cs
- hresults.cs
- KeyboardEventArgs.cs
- DynamicDocumentPaginator.cs
- SqlDataSourceConfigureFilterForm.cs
- StringTraceRecord.cs
- TextRenderer.cs
- PathGeometry.cs
- ScriptingProfileServiceSection.cs
- PersonalizationProvider.cs
- MarkedHighlightComponent.cs
- filewebrequest.cs
- MetabaseServerConfig.cs
- ToolboxControl.cs
- TransactionException.cs
- DataGridDefaultColumnWidthTypeConverter.cs
- HttpRequestBase.cs
- LazyInitializer.cs
- ObjectCacheHost.cs
- Parser.cs
- InsufficientExecutionStackException.cs
- ManagedIStream.cs
- CharAnimationUsingKeyFrames.cs