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