Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / DataOracleClient / System / Data / OracleClient / OracleParameterBinding.cs / 1 / 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
- HtmlUtf8RawTextWriter.cs
- OptionUsage.cs
- SiteMapDataSourceDesigner.cs
- AbstractDataSvcMapFileLoader.cs
- FreezableCollection.cs
- NodeInfo.cs
- Drawing.cs
- SingleTagSectionHandler.cs
- EventWaitHandleSecurity.cs
- LayoutEditorPart.cs
- BitmapEffectGeneralTransform.cs
- ElementMarkupObject.cs
- ButtonBaseDesigner.cs
- PasswordTextNavigator.cs
- Subtree.cs
- GraphicsPath.cs
- RoleManagerModule.cs
- GcHandle.cs
- OleDbTransaction.cs
- CngKeyBlobFormat.cs
- TraceHandlerErrorFormatter.cs
- ProvidePropertyAttribute.cs
- CurrentTimeZone.cs
- HttpAsyncResult.cs
- EditorZoneBase.cs
- RelationshipEntry.cs
- QueryComponents.cs
- CryptoStream.cs
- ConvertEvent.cs
- Accessible.cs
- TokenDescriptor.cs
- ThreadAbortException.cs
- DocumentViewerBase.cs
- XPathDocumentBuilder.cs
- CompositeControl.cs
- QueryTask.cs
- CultureInfo.cs
- XmlReturnWriter.cs
- DateTimeOffsetStorage.cs
- CodeDirectiveCollection.cs
- HtmlForm.cs
- XmlSchemaValidator.cs
- Pen.cs
- SafeNativeMethods.cs
- ChildrenQuery.cs
- CmsInterop.cs
- UIntPtr.cs
- InvalidateEvent.cs
- TreeViewBindingsEditorForm.cs
- ChangeInterceptorAttribute.cs
- DbReferenceCollection.cs
- SqlCharStream.cs
- DataException.cs
- SerialReceived.cs
- CodeStatement.cs
- OperationFormatUse.cs
- RunClient.cs
- Figure.cs
- PrivateFontCollection.cs
- ListContractAdapter.cs
- RuleValidation.cs
- DataSourceXmlClassAttribute.cs
- TypeUtil.cs
- JournalEntryListConverter.cs
- Roles.cs
- RightsManagementPermission.cs
- HashCodeCombiner.cs
- Int16AnimationBase.cs
- WebBrowserDocumentCompletedEventHandler.cs
- SHA384.cs
- TableLayoutSettingsTypeConverter.cs
- WebContext.cs
- SqlRetyper.cs
- MetaChildrenColumn.cs
- Substitution.cs
- SID.cs
- CodeDelegateInvokeExpression.cs
- StateMachineSubscription.cs
- CannotUnloadAppDomainException.cs
- KeyedCollection.cs
- ButtonFieldBase.cs
- Rotation3D.cs
- DocumentXmlWriter.cs
- XmlSchemaAttributeGroupRef.cs
- XmlSchemaElement.cs
- DebugHandleTracker.cs
- Object.cs
- DataGridViewCellCollection.cs
- XmlNodeChangedEventManager.cs
- AttributeUsageAttribute.cs
- TdsParserSafeHandles.cs
- NetStream.cs
- XPathDocumentNavigator.cs
- DATA_BLOB.cs
- _UncName.cs
- SystemIPGlobalStatistics.cs
- DbParameterCollectionHelper.cs
- NetPeerTcpBindingElement.cs
- CompositeFontFamily.cs
- ContainerParaClient.cs