internal Task WriteClose(StatementOrPortal type, string name, bool async, CancellationToken cancellationToken = default) { var len = sizeof(byte) + // Message code sizeof(int) + // Length sizeof(byte) + // Statement or portal name.Length + sizeof(byte); // Statement or portal name plus null terminator if (WriteBuffer.WriteSpaceLeft < 10) { return(FlushAndWrite(len, type, name, async, cancellationToken)); } Write(len, type, name); return(Task.CompletedTask); async Task FlushAndWrite(int len, StatementOrPortal type, string name, bool async, CancellationToken cancellationToken) { await Flush(async, cancellationToken); Debug.Assert(len <= WriteBuffer.WriteSpaceLeft, $"Message of type {GetType().Name} has length {len} which is bigger than the buffer ({WriteBuffer.WriteSpaceLeft})"); Write(len, type, name); } void Write(int len, StatementOrPortal type, string name) { WriteBuffer.WriteByte(FrontendMessageCode.Close); WriteBuffer.WriteInt32(len - 1); WriteBuffer.WriteByte((byte)type); WriteBuffer.WriteNullTerminatedString(name); } }
internal override void WriteFully(WriteBuffer buf) { Debug.Assert(Name != null && Name.All(c => c < 128)); buf.WriteByte(Code); buf.WriteInt32(Length - 1); buf.WriteByte((byte)StatementOrPortal); buf.WriteNullTerminatedString(Name); }
internal async Task WriteParse(string sql, string statementName, List <NpgsqlParameter> inputParameters, bool async, CancellationToken cancellationToken = default) { Debug.Assert(statementName.All(c => c < 128)); int queryByteLen; try { queryByteLen = TextEncoding.GetByteCount(sql); } catch (Exception e) { Break(e); throw; } if (WriteBuffer.WriteSpaceLeft < 1 + 4 + statementName.Length + 1) { await Flush(async, cancellationToken); } var messageLength = sizeof(byte) + // Message code sizeof(int) + // Length statementName.Length + // Statement name sizeof(byte) + // Null terminator for the statement name queryByteLen + sizeof(byte) + // SQL query length plus null terminator sizeof(ushort) + // Number of parameters inputParameters.Count * sizeof(int); // Parameter OIDs WriteBuffer.WriteByte(FrontendMessageCode.Parse); WriteBuffer.WriteInt32(messageLength - 1); WriteBuffer.WriteNullTerminatedString(statementName); await WriteBuffer.WriteString(sql, queryByteLen, async, cancellationToken); if (WriteBuffer.WriteSpaceLeft < 1 + 2) { await Flush(async, cancellationToken); } WriteBuffer.WriteByte(0); // Null terminator for the query WriteBuffer.WriteUInt16((ushort)inputParameters.Count); foreach (var p in inputParameters) { if (WriteBuffer.WriteSpaceLeft < 4) { await Flush(async, cancellationToken); } WriteBuffer.WriteInt32((int)p.Handler !.PostgresType.OID); } }
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 async Task WriteBind( List <NpgsqlParameter> parameters, string portal, string statement, bool allResultTypesAreUnknown, bool[]?unknownResultTypeList, bool async, CancellationToken cancellationToken = default) { Debug.Assert(statement.All(c => c < 128)); Debug.Assert(portal.All(c => c < 128)); var headerLength = sizeof(byte) + // Message code sizeof(int) + // Message length sizeof(byte) + // Portal is always empty (only a null terminator) statement.Length + sizeof(byte) + // Statement name plus null terminator sizeof(ushort); // Number of parameter format codes that follow if (WriteBuffer.WriteSpaceLeft < headerLength) { Debug.Assert(WriteBuffer.Size >= headerLength, "Write buffer too small for Bind header"); await Flush(async, cancellationToken); } var formatCodesSum = 0; var paramsLength = 0; for (var paramIndex = 0; paramIndex < parameters.Count; paramIndex++) { var param = parameters[paramIndex]; formatCodesSum += (int)param.FormatCode; param.LengthCache?.Rewind(); paramsLength += param.ValidateAndGetLength(); } var formatCodeListLength = formatCodesSum == 0 ? 0 : formatCodesSum == parameters.Count ? 1 : parameters.Count; var messageLength = headerLength + sizeof(short) * formatCodeListLength + // List of format codes sizeof(short) + // Number of parameters sizeof(int) * parameters.Count + // Parameter lengths paramsLength + // Parameter values sizeof(short) + // Number of result format codes sizeof(short) * (unknownResultTypeList?.Length ?? 1); // Result format codes WriteBuffer.WriteByte(FrontendMessageCode.Bind); WriteBuffer.WriteInt32(messageLength - 1); Debug.Assert(portal == string.Empty); WriteBuffer.WriteByte(0); // Portal is always empty WriteBuffer.WriteNullTerminatedString(statement); WriteBuffer.WriteInt16(formatCodeListLength); // 0 length implicitly means all-text, 1 means all-binary, >1 means mix-and-match if (formatCodeListLength == 1) { if (WriteBuffer.WriteSpaceLeft < 2) { await Flush(async, cancellationToken); } WriteBuffer.WriteInt16((short)FormatCode.Binary); } else if (formatCodeListLength > 1) { for (var paramIndex = 0; paramIndex < parameters.Count; paramIndex++) { if (WriteBuffer.WriteSpaceLeft < 2) { await Flush(async, cancellationToken); } WriteBuffer.WriteInt16((short)parameters[paramIndex].FormatCode); } } if (WriteBuffer.WriteSpaceLeft < 2) { await Flush(async, cancellationToken); } WriteBuffer.WriteUInt16((ushort)parameters.Count); for (var paramIndex = 0; paramIndex < parameters.Count; paramIndex++) { var param = parameters[paramIndex]; param.LengthCache?.Rewind(); await param.WriteWithLength(WriteBuffer, async, cancellationToken); } if (unknownResultTypeList != null) { if (WriteBuffer.WriteSpaceLeft < 2 + unknownResultTypeList.Length * 2) { await Flush(async, cancellationToken); } WriteBuffer.WriteInt16(unknownResultTypeList.Length); foreach (var t in unknownResultTypeList) { WriteBuffer.WriteInt16(t ? 0 : 1); } } else { if (WriteBuffer.WriteSpaceLeft < 4) { await Flush(async, cancellationToken); } WriteBuffer.WriteInt16(1); WriteBuffer.WriteInt16(allResultTypesAreUnknown ? 0 : 1); } }
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); } }