/// <summary> /// Helper method that updates all child expressions or statements /// by setting their parent to the immediate parent /// </summary> /// <param name="self">The item to update.</param> public static void UpdateParents(this Statement self) { var parents = new Stack <ASTItem>(); foreach (var n in self.All((item, type) => { if (!(item is Statement || item is Expression)) { return(false); } if (type == VisitorState.Enter) { if (item != self) { item.Parent = parents.Peek(); } parents.Push(item); } else if (type == VisitorState.Leave) { parents.Pop(); } return(true); })) { } if (parents.Count != 0) { throw new Exception($"{nameof(UpdateParents)} is broken ..."); } }
internal override async Task Write(NpgsqlWriteBuffer buf, bool async) { 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); } 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); if (buf.WriteSpaceLeft < 1 + 2) { await buf.Flush(async); } 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); } buf.WriteInt32((int)t); } }
/// <summary> /// Removes all <see cref="CaseGotoStatement"/>'s and inserts appropriate variables updates instead /// </summary> /// <returns>The statements without goto-statemtns.</returns> /// <param name="statement">The statements to update.</param> /// <param name="currentstate">The variable for the current state.</param> /// <param name="nextstate">The variable for the next clock state.</param> /// <param name="enumfields">The enum values for each state.</param> private Statement ReplaceGotoWithVariables(Statement statement, DataElement currentstate, DataElement nextstate, DataElement[] enumfields) { CaseGotoStatement current; while ((current = statement.All().OfType <CaseGotoStatement>().FirstOrDefault()) != null) { var fallThrough = current.FallThrough && current.CaseLabel < enumfields.Length; current.ReplaceWith( new ExpressionStatement( new AssignmentExpression( new IdentifierExpression(fallThrough ? currentstate : nextstate), new PrimitiveExpression(enumfields[current.CaseLabel % enumfields.Length].GetTarget().Name, enumfields[0].CecilType) ) ) ); } return(statement); }
internal override bool Write(NpgsqlBuffer buf, ref byte[] directBuf) { Contract.Requires(Statement != null && Statement.All(c => c < 128)); Contract.Requires(Portal != null && Portal.All(c => c < 128)); switch (_state) { case State.WroteNothing: var formatCodesSum = InputParameters.Select(p => p.FormatCode).Sum(c => (int)c); var formatCodeListLength = formatCodesSum == 0 ? 0 : formatCodesSum == InputParameters.Count ? 1 : InputParameters.Count; var headerLength = 4 + // Message length Portal.Length + 1 + Statement.Length + 1 + 2 + // Number of parameter format codes that follow 2 * formatCodeListLength + // List of format codes 2; // Number of parameters if (buf.WriteSpaceLeft < headerLength) { if (buf.Size < headerLength) { throw new Exception("Buffer too small for Bind header"); } return(false); } var messageLength = headerLength + 4 * InputParameters.Count + // Parameter lengths InputParameters.Select(p => p.BoundSize).Sum() + // Parameter values 2 + // Number of result format codes 2 * (UnknownResultTypeList == null ? 1 : UnknownResultTypeList.Length); // Result format codes buf.WriteByte(Code); buf.WriteInt32(messageLength); buf.WriteBytesNullTerminated(Encoding.ASCII.GetBytes(Portal)); buf.WriteBytesNullTerminated(Encoding.ASCII.GetBytes(Statement)); // 0 implicitly means all-text, 1 means all binary, >1 means mix-and-match buf.WriteInt16(formatCodeListLength); if (formatCodeListLength == 1) { buf.WriteInt16((short)FormatCode.Binary); } else if (formatCodeListLength > 1) { foreach (var code in InputParameters.Select(p => p.FormatCode)) { buf.WriteInt16((short)code); } } buf.WriteInt16(InputParameters.Count); _state = State.WroteHeader; goto case State.WroteHeader; case State.WroteHeader: if (!WriteParameters(buf, ref directBuf)) { return(false); } _state = State.WroteParameters; goto case State.WroteParameters; case State.WroteParameters: if (UnknownResultTypeList != null) { if (buf.WriteSpaceLeft < 2 + UnknownResultTypeList.Length * 2) { return(false); } buf.WriteInt16(UnknownResultTypeList.Length); foreach (var t in UnknownResultTypeList) { buf.WriteInt16(t ? 0 : 1); } } else { if (buf.WriteSpaceLeft < 4) { return(false); } buf.WriteInt16(1); buf.WriteInt16(AllResultTypesAreUnknown ? 0 : 1); } _state = State.Done; return(true); default: throw PGUtil.ThrowIfReached(); } }
internal override bool Write(NpgsqlBuffer buf, ref DirectBuffer directBuf) { Contract.Requires(Statement != null && Statement.All(c => c < 128)); switch (_state) { case State.WroteNothing: _statementNameBytes = PGUtil.UTF8Encoding.GetBytes(Statement); _queryLen = PGUtil.UTF8Encoding.GetByteCount(Query); if (buf.WriteSpaceLeft < 1 + 4 + _statementNameBytes.Length + 1) { return(false); } var messageLength = 1 + // Message code 4 + // Length _statementNameBytes.Length + 1 + // Null terminator _queryLen + 1 + // Null terminator 2 + // Number of parameters ParameterTypeOIDs.Count * 4; buf.WriteByte(Code); buf.WriteInt32(messageLength - 1); buf.WriteBytesNullTerminated(_statementNameBytes); goto case State.WroteHeader; case State.WroteHeader: _state = State.WroteHeader; if (_queryLen <= buf.WriteSpaceLeft) { buf.WriteString(Query); goto case State.WroteQuery; } if (_queryLen <= buf.Size) { // String can fit entirely in an empty buffer. Flush and retry rather than // going into the partial writing flow below (which requires ToCharArray()) return(false); } _queryChars = Query.ToCharArray(); _charPos = 0; goto case State.WritingQuery; case State.WritingQuery: _state = State.WritingQuery; int charsUsed; bool completed; buf.WriteStringChunked(_queryChars, _charPos, _queryChars.Length - _charPos, true, out charsUsed, out completed); if (!completed) { _charPos += charsUsed; return(false); } goto case State.WroteQuery; case State.WroteQuery: _state = State.WroteQuery; if (buf.WriteSpaceLeft < 1 + 2) { return(false); } buf.WriteByte(0); // Null terminator for the query buf.WriteInt16((short)ParameterTypeOIDs.Count); goto case State.WritingParameterTypes; case State.WritingParameterTypes: _state = State.WritingParameterTypes; for (; _parameterTypePos < ParameterTypeOIDs.Count; _parameterTypePos++) { if (buf.WriteSpaceLeft < 4) { return(false); } buf.WriteInt32((int)ParameterTypeOIDs[_parameterTypePos]); } _state = State.WroteAll; return(true); default: throw PGUtil.ThrowIfReached(); } }
internal bool Write(WriteBuffer buf, ref DirectBuffer directBuf) { Contract.Requires(Statement != null && Statement.All(c => c < 128)); Contract.Requires(Portal != null && Portal.All(c => c < 128)); switch (_state) { case State.Header: var formatCodesSum = InputParameters.Select(p => p.FormatCode).Sum(c => (int)c); _formatCodeListLength = formatCodesSum == 0 ? 0 : formatCodesSum == InputParameters.Count ? 1 : InputParameters.Count; var headerLength = 1 + // Message code 4 + // Message length Portal.Length + 1 + Statement.Length + 1 + 2; // Number of parameter format codes that follow if (buf.WriteSpaceLeft < headerLength) { Contract.Assume(buf.Size >= headerLength, "Buffer too small for Bind header"); return(false); } foreach (var c in InputParameters.Select(p => p.LengthCache).Where(c => c != null)) { c.Rewind(); } var messageLength = headerLength + 2 * _formatCodeListLength + // List of format codes 2 + // Number of parameters 4 * InputParameters.Count + // Parameter lengths InputParameters.Select(p => p.ValidateAndGetLength()).Sum() + // Parameter values 2 + // Number of result format codes 2 * (UnknownResultTypeList?.Length ?? 1); // Result format codes buf.WriteByte(Code); buf.WriteInt32(messageLength - 1); buf.WriteBytesNullTerminated(Encoding.ASCII.GetBytes(Portal)); buf.WriteBytesNullTerminated(Encoding.ASCII.GetBytes(Statement)); buf.WriteInt16(_formatCodeListLength); _paramIndex = 0; _state = State.ParameterFormatCodes; goto case State.ParameterFormatCodes; case State.ParameterFormatCodes: // 0 length implicitly means all-text, 1 means all-binary, >1 means mix-and-match if (_formatCodeListLength == 1) { if (buf.WriteSpaceLeft < 2) { return(false); } buf.WriteInt16((short)FormatCode.Binary); } else if (_formatCodeListLength > 1) { for (; _paramIndex < InputParameters.Count; _paramIndex++) { if (buf.WriteSpaceLeft < 2) { return(false); } buf.WriteInt16((short)InputParameters[_paramIndex].FormatCode); } } if (buf.WriteSpaceLeft < 2) { return(false); } buf.WriteInt16(InputParameters.Count); _paramIndex = 0; _state = State.ParameterValues; goto case State.ParameterValues; case State.ParameterValues: if (!WriteParameters(buf, ref directBuf)) { return(false); } _state = State.ResultFormatCodes; goto case State.ResultFormatCodes; case State.ResultFormatCodes: if (UnknownResultTypeList != null) { if (buf.WriteSpaceLeft < 2 + UnknownResultTypeList.Length * 2) { return(false); } buf.WriteInt16(UnknownResultTypeList.Length); foreach (var t in UnknownResultTypeList) { buf.WriteInt16(t ? 0 : 1); } } else { if (buf.WriteSpaceLeft < 4) { return(false); } buf.WriteInt16(1); buf.WriteInt16(AllResultTypesAreUnknown ? 0 : 1); } _state = State.Done; return(true); default: throw PGUtil.ThrowIfReached(); } }
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); } }