protected override async Task Write(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { Debug.Assert(_members != null); var composite = (T)value; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(_members.Count); foreach (var fieldDescriptor in _members) { var fieldHandler = fieldDescriptor.Handler; var fieldValue = fieldDescriptor.GetValue(composite); if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteUInt32(fieldDescriptor.OID); await fieldHandler.WriteWithLength(fieldValue, buf, lengthCache, null, async, cancellationToken); } }
async Task WriteBitArray(BitArray bitArray, WriteBuffer buf, bool async, CancellationToken cancellationToken) { // Initial bitlength byte if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(bitArray.Length); var byteLen = (bitArray.Length + 7) / 8; var pos = 0; while (true) { var endPos = pos + Math.Min(byteLen - pos, buf.WriteSpaceLeft); for (; pos < endPos; pos++) { var bitPos = pos * 8; var b = 0; for (var i = 0; i < Math.Min(8, bitArray.Length - bitPos); i++) { b += (bitArray[bitPos + i] ? 1 : 0) << (8 - i - 1); } buf.WriteByte((byte)b); } if (pos == byteLen) { return; } await buf.Flush(async, cancellationToken); } }
protected override async Task Write(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { var vector = (NpgsqlTsVector)value; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(vector.Count); foreach (var lexeme in vector) { if (buf.WriteSpaceLeft < MaxSingleLexemeBytes) { await buf.Flush(async, cancellationToken); } buf.WriteString(lexeme.Text); buf.WriteByte(0); buf.WriteInt16(lexeme.Count); for (var i = 0; i < lexeme.Count; i++) { buf.WriteInt16(lexeme[i].Value); } } }
protected override async Task Write(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { var query = (NpgsqlTsQuery)value; var numTokens = GetTokenCount(query); if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(numTokens); if (numTokens == 0) { return; } _stack.Push(query); while (_stack.Count > 0) { if (buf.WriteSpaceLeft < 2) { await buf.Flush(async, cancellationToken); } if (_stack.Peek().Kind == NpgsqlTsQuery.NodeKind.Lexeme && buf.WriteSpaceLeft < MaxSingleTokenBytes) { await buf.Flush(async, cancellationToken); } var node = _stack.Pop(); buf.WriteByte(node.Kind == NpgsqlTsQuery.NodeKind.Lexeme ? (byte)1 : (byte)2); if (node.Kind != NpgsqlTsQuery.NodeKind.Lexeme) { buf.WriteByte((byte)node.Kind); if (node.Kind == NpgsqlTsQuery.NodeKind.Not) { _stack.Push(((NpgsqlTsQueryNot)node).Child); } else { _stack.Push(((NpgsqlTsQueryBinOp)node).Right); _stack.Push(((NpgsqlTsQueryBinOp)node).Left); } } else { var lexemeNode = (NpgsqlTsQueryLexeme)node; buf.WriteByte((byte)lexemeNode.Weights); buf.WriteByte(lexemeNode.IsPrefixSearch ? (byte)1 : (byte)0); buf.WriteString(lexemeNode.Text); buf.WriteByte(0); } } _stack.Clear(); }
async Task WriteString(string str, WriteBuffer buf, bool async, CancellationToken cancellationToken) { // Initial bitlength byte if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(str.Length); var pos = 0; var byteLen = (str.Length + 7) / 8; var bytePos = 0; while (true) { var endBytePos = bytePos + Math.Min(byteLen - bytePos - 1, buf.WriteSpaceLeft); for (; bytePos < endBytePos; bytePos++) { var b = 0; b += (str[pos++] - '0') << 7; b += (str[pos++] - '0') << 6; b += (str[pos++] - '0') << 5; b += (str[pos++] - '0') << 4; b += (str[pos++] - '0') << 3; b += (str[pos++] - '0') << 2; b += (str[pos++] - '0') << 1; b += (str[pos++] - '0'); buf.WriteByte((byte)b); } if (bytePos >= byteLen - 1) { break; } await buf.Flush(async, cancellationToken); } if (pos < str.Length) { if (buf.WriteSpaceLeft < 1) { await buf.Flush(async, cancellationToken); } var remainder = str.Length - pos; var lastChunk = 0; for (var i = 7; i >= 8 - remainder; i--) { lastChunk += (str[pos++] - '0') << i; } buf.WriteByte((byte)lastChunk); } }
protected override async Task Write(object value, WriteBuffer buf, LengthCache lengthCache, [CanBeNull] NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { ArraySegment <byte> segment; if (value is ArraySegment <byte> ) { segment = (ArraySegment <byte>)value; if (!(parameter == null || parameter.Size <= 0 || parameter.Size >= segment.Count)) { segment = new ArraySegment <byte>(segment.Array, segment.Offset, parameter.Size); } } else { var array = (byte[])value; var len = parameter == null || parameter.Size <= 0 || parameter.Size >= array.Length ? array.Length : parameter.Size; segment = new ArraySegment <byte>(array, 0, len); } // The entire segment fits in our buffer, copy it as usual. if (segment.Count <= buf.WriteSpaceLeft) { buf.WriteBytes(segment.Array, segment.Offset, segment.Count); return; } // The segment is larger than our buffer. Flush whatever is currently in the buffer and // write the array directly to the socket. await buf.Flush(async, cancellationToken); buf.DirectWrite(segment.Array, segment.Offset, segment.Count); }
internal async Task WriteSASLInitialResponse(string mechanism, byte[] initialResponse, bool async, CancellationToken cancellationToken = default) { var len = sizeof(byte) + // Message code sizeof(int) + // Length PGUtil.UTF8Encoding.GetByteCount(mechanism) + sizeof(byte) + // Mechanism plus null terminator sizeof(int) + // Initial response length (initialResponse?.Length ?? 0); // Initial response payload if (WriteBuffer.WriteSpaceLeft < len) { await WriteBuffer.Flush(async, cancellationToken); } WriteBuffer.WriteByte(FrontendMessageCode.Password); WriteBuffer.WriteInt32(len - 1); WriteBuffer.WriteString(mechanism); WriteBuffer.WriteByte(0); // null terminator if (initialResponse == null) { WriteBuffer.WriteInt32(-1); } else { WriteBuffer.WriteInt32(initialResponse.Length); WriteBuffer.WriteBytes(initialResponse); } }
async Task AuthenticateMD5(string username, byte[] salt, bool async) { var passwd = Settings.Password; // No password was provided. Attempt to pull the password from the pgpass file. if (passwd == null) { var matchingEntry = PgPassFile.Load(Settings.Passfile)?.GetFirstMatchingEntry(Settings.Host, Settings.Port, Settings.Database, Settings.Username); if (matchingEntry != null) { Log.Trace("Taking password from pgpass file"); passwd = matchingEntry.Password; } } if (passwd == null) { throw new NpgsqlException("No password has been provided but the backend requires one (in MD5)"); } await PasswordMessage .CreateMD5(passwd, username, salt) .Write(WriteBuffer, async); await WriteBuffer.Flush(async); await ReadExpecting <AuthenticationRequestMessage>(async); }
async Task WriteBool(bool b, WriteBuffer buf, bool async, CancellationToken cancellationToken) { if (buf.WriteSpaceLeft < 5) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(1); buf.WriteByte(b ? (byte)0x80 : (byte)0); }
protected override async Task Write(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { if (buf.WriteSpaceLeft < 1) { await buf.Flush(async, cancellationToken); } buf.WriteByte(JsonbProtocolVersion); await base.Write(value, buf, lengthCache, parameter, async, cancellationToken); }
internal override async Task Write(WriteBuffer buf, bool async, CancellationToken cancellationToken) { Debug.Assert(Statement != null && Statement.All(c => c < 128)); var queryByteLen = _encoding.GetByteCount(Query); if (buf.WriteSpaceLeft < 1 + 4 + Statement.Length + 1) { await buf.Flush(async, cancellationToken); } var messageLength = 1 + // Message code 4 + // Length Statement.Length + 1 + // Null terminator queryByteLen + 1 + // Null terminator 2 + // Number of parameters ParameterTypeOIDs.Count * 4; buf.WriteByte(Code); buf.WriteInt32(messageLength - 1); buf.WriteNullTerminatedString(Statement); await buf.WriteString(Query, queryByteLen, async, cancellationToken); if (buf.WriteSpaceLeft < 1 + 2) { await buf.Flush(async, cancellationToken); } buf.WriteByte(0); // Null terminator for the query buf.WriteInt16((short)ParameterTypeOIDs.Count); foreach (var t in ParameterTypeOIDs) { if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32((int)t); } }
internal override async Task Write(WriteBuffer buf, bool async, CancellationToken cancellationToken) { if (buf.WriteSpaceLeft < 1 + 5) { await buf.Flush(async); } buf.WriteByte(Code); buf.WriteInt32(4 + PayloadLength); if (PayloadLength <= buf.WriteSpaceLeft) { // The entire array fits in our buffer, copy it into the buffer as usual. buf.WriteBytes(Payload, PayloadOffset, Payload.Length); return; } await buf.Flush(async); buf.DirectWrite(Payload, PayloadOffset, PayloadLength); }
internal override async Task Write(WriteBuffer buf, bool async, CancellationToken cancellationToken) { if (buf.WriteSpaceLeft < 1 + 4) { await buf.Flush(async, cancellationToken); } var queryByteLen = _encoding.GetByteCount(_query); buf.WriteByte(Code); buf.WriteInt32(4 + // Message length (including self excluding code) queryByteLen + // Query byte length 1); // Null terminator await buf.WriteString(_query, queryByteLen, async, cancellationToken); if (buf.WriteSpaceLeft < 1) { await buf.Flush(async, cancellationToken); } buf.WriteByte(0); }
protected override async Task Write(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { var polygon = (NpgsqlPolygon)value; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(polygon.Count); foreach (var p in polygon) { if (buf.WriteSpaceLeft < 16) { await buf.Flush(async, cancellationToken); } buf.WriteDouble(p.X); buf.WriteDouble(p.Y); } }
protected override async Task Write(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { var path = (NpgsqlPath)value; if (buf.WriteSpaceLeft < 5) { await buf.Flush(async, cancellationToken); } buf.WriteByte((byte)(path.Open ? 0 : 1)); buf.WriteInt32(path.Count); foreach (var p in path) { if (buf.WriteSpaceLeft < 16) { await buf.Flush(async, cancellationToken); } buf.WriteDouble(p.X); buf.WriteDouble(p.Y); } }
static PregeneratedMessage BuildQuery(string query) { Contract.Requires(query != null && query.All(c => c < 128)); var totalLen = 5 + query.Length; var ms = new MemoryStream(totalLen); _tempBuf.Underlying = ms; _tempQuery.Populate(query); _tempQuery.Write(_tempBuf); _tempBuf.Flush(); return(new PregeneratedMessage(ms.ToArray(), _tempQuery.ToString())); }
async Task WriteBitVector32(BitVector32 bitVector, WriteBuffer buf, bool async, CancellationToken cancellationToken) { if (buf.WriteSpaceLeft < 8) { await buf.Flush(async, cancellationToken); } if (bitVector.Data == 0) { buf.WriteInt32(0); } else { buf.WriteInt32(32); buf.WriteInt32(bitVector.Data); } }
internal async Task WritePassword(byte[] payload, int offset, int count, bool async, CancellationToken cancellationToken = default) { if (WriteBuffer.WriteSpaceLeft < sizeof(byte) + sizeof(int)) { await WriteBuffer.Flush(async, cancellationToken); } WriteBuffer.WriteByte(FrontendMessageCode.Password); WriteBuffer.WriteInt32(sizeof(int) + count); if (count <= WriteBuffer.WriteSpaceLeft) { // The entire array fits in our WriteBuffer, copy it into the WriteBuffer as usual. WriteBuffer.WriteBytes(payload, offset, count); return; } await WriteBuffer.Flush(async, cancellationToken); await WriteBuffer.DirectWrite(new ReadOnlyMemory <byte>(payload, offset, count), async, cancellationToken); }
protected override async Task Write(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { var asDict = (IDictionary <string, string>)value; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(asDict.Count); if (asDict.Count == 0) { return; } foreach (var kv in asDict) { await _textHandler.WriteWithLength(kv.Key, buf, lengthCache, parameter, async, cancellationToken); await _textHandler.WriteWithLength(kv.Value, buf, lengthCache, parameter, async, cancellationToken); } }
protected override async Task Write(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { var range = (NpgsqlRange <TElement>)value; if (buf.WriteSpaceLeft < 1) { await buf.Flush(async, cancellationToken); } buf.WriteByte((byte)range.Flags); if (range.IsEmpty) { return; } if (!range.LowerBoundInfinite) { await ElementHandler.WriteWithLength(range.LowerBound, buf, lengthCache, null, async, cancellationToken); } if (!range.UpperBoundInfinite) { await ElementHandler.WriteWithLength(range.UpperBound, buf, lengthCache, null, async, cancellationToken); } }
internal Task Flush(bool async, CancellationToken cancellationToken = default) => WriteBuffer.Flush(async, cancellationToken);
internal void Flush() => WriteBuffer.Flush(false).GetAwaiter().GetResult();
internal override async Task Write(WriteBuffer buf, bool async, CancellationToken cancellationToken) { Debug.Assert(Statement != null && Statement.All(c => c < 128)); Debug.Assert(Portal != null && Portal.All(c => c < 128)); var headerLength = 1 + // Message code 4 + // Message length 1 + // Portal is always empty (only a null terminator) Statement.Length + 1 + 2; // Number of parameter format codes that follow if (buf.WriteSpaceLeft < headerLength) { Debug.Assert(buf.Size >= headerLength, "Buffer too small for Bind header"); await buf.Flush(async, cancellationToken); } var formatCodesSum = 0; var paramsLength = 0; foreach (var p in InputParameters) { formatCodesSum += (int)p.FormatCode; p.LengthCache?.Rewind(); paramsLength += p.ValidateAndGetLength(); } var formatCodeListLength = formatCodesSum == 0 ? 0 : formatCodesSum == InputParameters.Count ? 1 : InputParameters.Count; var messageLength = headerLength + 2 * formatCodeListLength + // List of format codes 2 + // Number of parameters 4 * InputParameters.Count + // Parameter lengths paramsLength + // Parameter values 2 + // Number of result format codes 2 * (UnknownResultTypeList?.Length ?? 1); // Result format codes buf.WriteByte(Code); buf.WriteInt32(messageLength - 1); Debug.Assert(Portal == string.Empty); buf.WriteByte(0); // Portal is always empty buf.WriteNullTerminatedString(Statement); buf.WriteInt16(formatCodeListLength); // 0 length implicitly means all-text, 1 means all-binary, >1 means mix-and-match if (formatCodeListLength == 1) { if (buf.WriteSpaceLeft < 2) { await buf.Flush(async, cancellationToken); } buf.WriteInt16((short)FormatCode.Binary); } else if (formatCodeListLength > 1) { foreach (NpgsqlParameter p in InputParameters) { if (buf.WriteSpaceLeft < 2) { await buf.Flush(async, cancellationToken); } buf.WriteInt16((short)p.FormatCode); } } if (buf.WriteSpaceLeft < 2) { await buf.Flush(async, cancellationToken); } buf.WriteInt16(InputParameters.Count); foreach (var param in InputParameters) { param.LengthCache?.Rewind(); await param.WriteWithLength(buf, async, cancellationToken); } if (UnknownResultTypeList != null) { if (buf.WriteSpaceLeft < 2 + UnknownResultTypeList.Length * 2) { await buf.Flush(async, cancellationToken); } buf.WriteInt16(UnknownResultTypeList.Length); foreach (var t in UnknownResultTypeList) { buf.WriteInt16(t ? 0 : 1); } } else { if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt16(1); buf.WriteInt16(AllResultTypesAreUnknown ? 0 : 1); } }
async Task Write(PostgisGeometry geom, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter, bool async, CancellationToken cancellationToken) { // Common header if (geom.SRID == 0) { if (buf.WriteSpaceLeft < 5) { await buf.Flush(async, cancellationToken); } buf.WriteByte(0); // We choose to ouput only XDR structure buf.WriteInt32((int)geom.Identifier); } else { if (buf.WriteSpaceLeft < 9) { await buf.Flush(async, cancellationToken); } buf.WriteByte(0); buf.WriteInt32((int)((uint)geom.Identifier | (uint)EwkbModifiers.HasSRID)); buf.WriteInt32((int)geom.SRID); } switch (geom.Identifier) { case WkbIdentifier.Point: if (buf.WriteSpaceLeft < 16) { await buf.Flush(async, cancellationToken); } var p = (PostgisPoint)geom; buf.WriteDouble(p.X); buf.WriteDouble(p.Y); return; case WkbIdentifier.LineString: var l = (PostgisLineString)geom; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(l.PointCount); for (var ipts = 0; ipts < l.PointCount; ipts++) { if (buf.WriteSpaceLeft < 16) { await buf.Flush(async, cancellationToken); } buf.WriteDouble(l[ipts].X); buf.WriteDouble(l[ipts].Y); } return; case WkbIdentifier.Polygon: var pol = (PostgisPolygon)geom; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(pol.RingCount); for (var irng = 0; irng < pol.RingCount; irng++) { if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(pol[irng].Length); for (var ipts = 0; ipts < pol[irng].Length; ipts++) { if (buf.WriteSpaceLeft < 16) { await buf.Flush(async, cancellationToken); } buf.WriteDouble(pol[irng][ipts].X); buf.WriteDouble(pol[irng][ipts].Y); } } return; case WkbIdentifier.MultiPoint: var mp = (PostgisMultiPoint)geom; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(mp.PointCount); for (var ipts = 0; ipts < mp.PointCount; ipts++) { if (buf.WriteSpaceLeft < 21) { await buf.Flush(async, cancellationToken); } buf.WriteByte(0); buf.WriteInt32((int)WkbIdentifier.Point); buf.WriteDouble(mp[ipts].X); buf.WriteDouble(mp[ipts].Y); } return; case WkbIdentifier.MultiLineString: var ml = (PostgisMultiLineString)geom; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(ml.LineCount); for (var irng = 0; irng < ml.LineCount; irng++) { if (buf.WriteSpaceLeft < 9) { await buf.Flush(async, cancellationToken); } buf.WriteByte(0); buf.WriteInt32((int)WkbIdentifier.LineString); buf.WriteInt32(ml[irng].PointCount); for (var ipts = 0; ipts < ml[irng].PointCount; ipts++) { if (buf.WriteSpaceLeft < 16) { await buf.Flush(async, cancellationToken); } buf.WriteDouble(ml[irng][ipts].X); buf.WriteDouble(ml[irng][ipts].Y); } } return; case WkbIdentifier.MultiPolygon: var mpl = (PostgisMultiPolygon)geom; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(mpl.PolygonCount); for (var ipol = 0; ipol < mpl.PolygonCount; ipol++) { if (buf.WriteSpaceLeft < 9) { await buf.Flush(async, cancellationToken); } buf.WriteByte(0); buf.WriteInt32((int)WkbIdentifier.Polygon); buf.WriteInt32(mpl[ipol].RingCount); for (var irng = 0; irng < mpl[ipol].RingCount; irng++) { if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(mpl[ipol][irng].Length); for (var ipts = 0; ipts < mpl[ipol][irng].Length; ipts++) { if (buf.WriteSpaceLeft < 16) { await buf.Flush(async, cancellationToken); } buf.WriteDouble(mpl[ipol][irng][ipts].X); buf.WriteDouble(mpl[ipol][irng][ipts].Y); } } } return; case WkbIdentifier.GeometryCollection: var coll = (PostgisGeometryCollection)geom; if (buf.WriteSpaceLeft < 4) { await buf.Flush(async, cancellationToken); } buf.WriteInt32(coll.GeometryCount); foreach (var x in coll) { await Write(x, buf, lengthCache, null, async, cancellationToken); } return; default: throw new InvalidOperationException("Unknown Postgis identifier."); } }