Beispiel #1
0
        public override void Write(byte[] buffer, int offset, int count)
        {
            CheckDisposed();
            if (!CanWrite)
            {
                throw new InvalidOperationException("Stream not open for writing");
            }

            if (count == 0)
            {
                return;
            }

            EnsureDataMessage();

            if (count <= _buf.WriteSpaceLeft)
            {
                _buf.WriteBytesSimple(buffer, offset, count);
                return;
            }

            // Buffer is too big. Write whatever will fit and flush.
            var written = _buf.WriteSpaceLeft;

            _buf.WriteBytesSimple(buffer, offset, _buf.WriteSpaceLeft);
            Flush();

            offset += written;
            count  -= written;

            // If the remainder fits in a single buffer, no problem.
            if (count <= _buf.WriteSpaceLeft)
            {
                EnsureDataMessage();
                _buf.WriteBytesSimple(buffer, offset, count);
                return;
            }

            // Otherwise, write the CopyData header via our buffer and the remaining data directly to the socket
            _buf.WriteByte((byte)BackendMessageCode.CopyData);
            _buf.WriteInt32(count);
            _buf.Flush();
            _buf.Underlying.Write(buffer, offset, count);
        }
Beispiel #2
0
        public override void Write(byte[] buffer, int offset, int count)
        {
            CheckDisposed();
            if (!CanWrite)
            {
                throw new InvalidOperationException("Stream not open for writing");
            }

            if (count == 0)
            {
                return;
            }

            EnsureDataMessage();

            if (count <= _buf.WriteSpaceLeft)
            {
                _buf.WriteBytes(buffer, offset, count);
                return;
            }

            try {
                // Value is too big. Flush whatever is in the buffer, then write a new CopyData
                // directly with the buffer.
                Flush();

                _buf.WriteByte((byte)BackendMessageCode.CopyData);
                _buf.WriteInt32(count + 4);
                _buf.Flush();
                _buf.Underlying.Write(buffer, offset, count);
                EnsureDataMessage();
            } catch {
                _connector.Break();
                Cleanup();
                throw;
            }
        }
Beispiel #3
0
        void Flush()
        {
            if (!_writingDataMsg)
            {
                return;
            }

            // Need to update the length for the CopyData about to be sent
            var pos = _buf.WritePosition;

            _buf.WritePosition = 1;
            _buf.WriteInt32(pos - 1);
            _buf.WritePosition = pos;
            _buf.Flush();
            _writingDataMsg = false;
        }
        void DoWrite <T>(TypeHandler handler, T value)
        {
            try
            {
                if (_buf.WriteSpaceLeft < 4)
                {
                    FlushAndStartDataMessage();
                }

                var asObject = (object)value;  // TODO: Implement boxless writing in the future
                if (asObject == null)
                {
                    _buf.WriteInt32(-1);
                    _column++;
                    return;
                }

                _dummyParam.ConvertedValue = null;

                var asSimple = handler as ISimpleTypeWriter;
                if (asSimple != null)
                {
                    var len = asSimple.ValidateAndGetLength(asObject, _dummyParam);
                    _buf.WriteInt32(len);
                    if (_buf.WriteSpaceLeft < len)
                    {
                        Contract.Assume(_buf.Size >= len);
                        FlushAndStartDataMessage();
                    }
                    asSimple.Write(asObject, _buf, _dummyParam);
                    _column++;
                    return;
                }

                var asChunking = handler as IChunkingTypeWriter;
                if (asChunking != null)
                {
                    _lengthCache.Clear();
                    var len = asChunking.ValidateAndGetLength(asObject, ref _lengthCache, _dummyParam);
                    _buf.WriteInt32(len);

                    // If the type handler used the length cache, rewind it to skip the first position:
                    // it contains the entire value length which we already have in len.
                    if (_lengthCache.Position > 0)
                    {
                        _lengthCache.Rewind();
                        _lengthCache.Position++;
                    }

                    asChunking.PrepareWrite(asObject, _buf, _lengthCache, _dummyParam);
                    var directBuf = new DirectBuffer();
                    while (!asChunking.Write(ref directBuf))
                    {
                        Flush();

                        // The following is an optimization hack for writing large byte arrays without passing
                        // through our buffer
                        if (directBuf.Buffer != null)
                        {
                            len = directBuf.Size == 0 ? directBuf.Buffer.Length : directBuf.Size;
                            _buf.WritePosition = 1;
                            _buf.WriteInt32(len + 4);
                            _buf.Flush();
                            _writingDataMsg = false;
                            _buf.Underlying.Write(directBuf.Buffer, directBuf.Offset, len);
                            directBuf.Buffer = null;
                            directBuf.Size   = 0;
                        }
                        EnsureDataMessage();
                    }
                    _column++;
                    return;
                }

                throw PGUtil.ThrowIfReached();
            }
            catch
            {
                _connector.Break();
                Cleanup();
                throw;
            }
        }