//////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // // Methods // //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// internal void Bind( OciHandle statementHandle, NativeBuffer parameterBuffer, OracleConnection connection ) { 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; OciHandle errorHandle = connection.ErrorHandle; OciHandle environmentHandle = connection.EnvironmentHandle; int valueLength = 0; OCI.INDICATOR indicatorValue = OCI.INDICATOR.OK; int bufferLength; OCI.DATATYPE ociType = _bindingMetaType.OciType; HandleRef indicatorLocation = parameterBuffer.PtrOffset(_indicatorOffset); HandleRef lengthLocation = parameterBuffer.PtrOffset(_lengthOffset); HandleRef valueLocation = parameterBuffer.PtrOffset(_valueOffset); if (IsDirection(Parameter, ParameterDirection.Input)) { if (ADP.IsNull(_coercedValue)) { indicatorValue = OCI.INDICATOR.ISNULL; } else { valueLength = PutOracleValue( _coercedValue, valueLocation, _bindingMetaType, connection); } } 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 = _bufferLengthInBytes; // ...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); break; case OCI.DATATYPE.RSET: _descriptor = new OciStatementHandle(environmentHandle); break; } if (null != _locator) { Marshal.WriteIntPtr((IntPtr)valueLocation, (IntPtr)_locator.Handle); } else if (null != _descriptor) { Marshal.WriteIntPtr((IntPtr)valueLocation, (IntPtr)_descriptor.Handle); } } Marshal.WriteInt16((IntPtr)indicatorLocation, (Int16)indicatorValue); // 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 = ADP.NullHandleRef; } else { // When we're binding this parameter as UCS2, the length we specify // must be in characters, not in bytes. if (_bindAsUCS2) { Marshal.WriteInt32((IntPtr)lengthLocation, (Int32)(valueLength / ADP.CharSize)); } else { Marshal.WriteInt32((IntPtr)lengthLocation, (Int32)valueLength); } } if (IsDirection(Parameter, ParameterDirection.Output)) { bufferLength = _bufferLengthInBytes; } else { bufferLength = valueLength; } // Finally, tell Oracle about our parameter. int rc = TracedNativeMethods.OCIBindByName( statementHandle, out h, errorHandle, parameterName, parameterName.Length, valueLocation, bufferLength, ociType, indicatorLocation, lengthLocation, ADP.NullHandleRef, 0, ADP.NullHandleRef, 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)_bufferLength, 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, OCI.OCI_UCS2ID, errorHandle); } } }