////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////
        //
        // 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);
                }
            }
        }