public async Task <ResultSet> ReadResultSetHeaderAsync(IOBehavior ioBehavior) { // ResultSet can be re-used, so initialize everything BufferState = ResultSetState.None; ColumnDefinitions = null; ColumnTypes = null; LastInsertId = 0; RecordsAffected = null; State = ResultSetState.None; m_columnDefinitionPayloadUsedBytes = 0; m_dataLengths = null; m_dataOffsets = null; m_readBuffer.Clear(); m_row = null; m_rowBuffered = null; m_hasRows = false; try { while (true) { var payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); var firstByte = payload.HeaderByte; if (firstByte == OkPayload.Signature) { var ok = OkPayload.Create(payload); RecordsAffected = (RecordsAffected ?? 0) + ok.AffectedRowCount; LastInsertId = unchecked ((long)ok.LastInsertId); if (ok.NewSchema != null) { Connection.Session.DatabaseOverride = ok.NewSchema; } ColumnDefinitions = null; ColumnTypes = null; State = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; if (State == ResultSetState.NoMoreData) { break; } } else if (firstByte == LocalInfilePayload.Signature) { try { var localInfile = LocalInfilePayload.Create(payload); if (!IsHostVerified(Connection) && !localInfile.FileName.StartsWith(MySqlBulkLoader.StreamPrefix, StringComparison.Ordinal)) { throw new NotSupportedException("Use SourceStream or SslMode >= VerifyCA for LOAD DATA LOCAL INFILE"); } using (var stream = localInfile.FileName.StartsWith(MySqlBulkLoader.StreamPrefix, StringComparison.Ordinal) ? MySqlBulkLoader.GetAndRemoveStream(localInfile.FileName) : File.OpenRead(localInfile.FileName)) { byte[] readBuffer = new byte[65536]; int byteCount; while ((byteCount = await stream.ReadAsync(readBuffer, 0, readBuffer.Length).ConfigureAwait(false)) > 0) { payload = new PayloadData(new ArraySegment <byte>(readBuffer, 0, byteCount)); await Session.SendReplyAsync(payload, ioBehavior, CancellationToken.None).ConfigureAwait(false); } } } catch (Exception ex) { // store the exception, to be thrown after reading the response packet from the server ReadResultSetHeaderException = new MySqlException("Error during LOAD DATA LOCAL INFILE", ex); } await Session.SendReplyAsync(EmptyPayload.Create(), ioBehavior, CancellationToken.None).ConfigureAwait(false); } else { int ReadColumnCount(ArraySegment <byte> arraySegment) { var reader = new ByteArrayReader(arraySegment); var columnCount_ = (int)reader.ReadLengthEncodedInteger(); if (reader.BytesRemaining != 0) { throw new MySqlException("Unexpected data at end of column_count packet; see https://github.com/mysql-net/MySqlConnector/issues/324"); } return(columnCount_); } var columnCount = ReadColumnCount(payload.ArraySegment); // reserve adequate space to hold a copy of all column definitions (but note that this can be resized below if we guess too small) Array.Resize(ref m_columnDefinitionPayloads, columnCount * 96); ColumnDefinitions = new ColumnDefinitionPayload[columnCount]; ColumnTypes = new MySqlDbType[columnCount]; m_dataOffsets = new int[columnCount]; m_dataLengths = new int[columnCount]; for (var column = 0; column < ColumnDefinitions.Length; column++) { payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); var arraySegment = payload.ArraySegment; // 'Session.ReceiveReplyAsync' reuses a shared buffer; make a copy so that the column definitions can always be safely read at any future point if (m_columnDefinitionPayloadUsedBytes + arraySegment.Count > m_columnDefinitionPayloads.Length) { Array.Resize(ref m_columnDefinitionPayloads, Math.Max(m_columnDefinitionPayloadUsedBytes + arraySegment.Count, m_columnDefinitionPayloadUsedBytes * 2)); } Buffer.BlockCopy(arraySegment.Array, arraySegment.Offset, m_columnDefinitionPayloads, m_columnDefinitionPayloadUsedBytes, arraySegment.Count); var columnDefinition = ColumnDefinitionPayload.Create(new ArraySegment <byte>(m_columnDefinitionPayloads, m_columnDefinitionPayloadUsedBytes, arraySegment.Count)); ColumnDefinitions[column] = columnDefinition; ColumnTypes[column] = TypeMapper.ConvertToMySqlDbType(columnDefinition, treatTinyAsBoolean: Connection.TreatTinyAsBoolean, guidFormat: Connection.GuidFormat); m_columnDefinitionPayloadUsedBytes += arraySegment.Count; } if (!Session.SupportsDeprecateEof) { payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); EofPayload.Create(payload); } LastInsertId = -1; State = ResultSetState.ReadResultSetHeader; break; } } } catch (Exception ex) { ReadResultSetHeaderException = ex; } finally { BufferState = State; } return(this); }
public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior) { Reset(); try { while (true) { var payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); var firstByte = payload.HeaderByte; if (firstByte == OkPayload.Signature) { var ok = OkPayload.Create(payload.Span, Session.SupportsDeprecateEof, Session.SupportsSessionTrack); RecordsAffected = (RecordsAffected ?? 0) + ok.AffectedRowCount; LastInsertId = unchecked ((long)ok.LastInsertId); WarningCount = ok.WarningCount; if (ok.NewSchema is object) { Connection.Session.DatabaseOverride = ok.NewSchema; } ColumnDefinitions = null; ColumnTypes = null; State = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; if (State == ResultSetState.NoMoreData) { break; } } else if (firstByte == LocalInfilePayload.Signature) { try { if (!Connection.AllowLoadLocalInfile) { throw new NotSupportedException("To use LOAD DATA LOCAL INFILE, set AllowLoadLocalInfile=true in the connection string. See https://fl.vu/mysql-load-data"); } var localInfile = LocalInfilePayload.Create(payload.Span); if (!IsHostVerified(Connection) && !localInfile.FileName.StartsWith(MySqlBulkLoader.StreamPrefix, StringComparison.Ordinal)) { throw new NotSupportedException("Use SourceStream or SslMode >= VerifyCA for LOAD DATA LOCAL INFILE. See https://fl.vu/mysql-load-data"); } using var stream = localInfile.FileName.StartsWith(MySqlBulkLoader.StreamPrefix, StringComparison.Ordinal) ? MySqlBulkLoader.GetAndRemoveStream(localInfile.FileName) : File.OpenRead(localInfile.FileName); var readBuffer = new byte[65536]; int byteCount; while ((byteCount = await stream.ReadAsync(readBuffer, 0, readBuffer.Length).ConfigureAwait(false)) > 0) { payload = new PayloadData(new ArraySegment <byte>(readBuffer, 0, byteCount)); await Session.SendReplyAsync(payload, ioBehavior, CancellationToken.None).ConfigureAwait(false); } } catch (Exception ex) { // store the exception, to be thrown after reading the response packet from the server ReadResultSetHeaderException = new MySqlException("Error during LOAD DATA LOCAL INFILE", ex); } await Session.SendReplyAsync(EmptyPayload.Instance, ioBehavior, CancellationToken.None).ConfigureAwait(false); } else { int ReadColumnCount(ReadOnlySpan <byte> span) { var reader = new ByteArrayReader(span); var columnCount_ = (int)reader.ReadLengthEncodedInteger(); if (reader.BytesRemaining != 0) { throw new MySqlException("Unexpected data at end of column_count packet; see https://github.com/mysql-net/MySqlConnector/issues/324"); } return(columnCount_); } var columnCount = ReadColumnCount(payload.Span); // reserve adequate space to hold a copy of all column definitions (but note that this can be resized below if we guess too small) Utility.Resize(ref m_columnDefinitionPayloads, columnCount * 96); ColumnDefinitions = new ColumnDefinitionPayload[columnCount]; ColumnTypes = new MySqlDbType[columnCount]; for (var column = 0; column < ColumnDefinitions.Length; column++) { payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); var payloadLength = payload.Span.Length; // 'Session.ReceiveReplyAsync' reuses a shared buffer; make a copy so that the column definitions can always be safely read at any future point if (m_columnDefinitionPayloadUsedBytes + payloadLength > m_columnDefinitionPayloads.Count) { Utility.Resize(ref m_columnDefinitionPayloads, m_columnDefinitionPayloadUsedBytes + payloadLength); } payload.Span.CopyTo(m_columnDefinitionPayloads.Array.AsSpan().Slice(m_columnDefinitionPayloadUsedBytes)); var columnDefinition = ColumnDefinitionPayload.Create(new ResizableArraySegment <byte>(m_columnDefinitionPayloads, m_columnDefinitionPayloadUsedBytes, payloadLength)); ColumnDefinitions[column] = columnDefinition; ColumnTypes[column] = TypeMapper.ConvertToMySqlDbType(columnDefinition, treatTinyAsBoolean: Connection.TreatTinyAsBoolean, guidFormat: Connection.GuidFormat); m_columnDefinitionPayloadUsedBytes += payloadLength; } if (!Session.SupportsDeprecateEof) { payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); EofPayload.Create(payload.Span); } if (ColumnDefinitions.Length == (Command?.OutParameters?.Count + 1) && ColumnDefinitions[0].Name == SingleCommandPayloadCreator.OutParameterSentinelColumnName) { ContainsCommandParameters = true; } LastInsertId = -1; WarningCount = 0; State = ResultSetState.ReadResultSetHeader; break; } } } catch (Exception ex) { ReadResultSetHeaderException = ex; } finally { BufferState = State; } }
public async Task <ResultSet> ReadResultSetHeaderAsync(IOBehavior ioBehavior) { // ResultSet can be re-used, so initialize everything BufferState = ResultSetState.None; ColumnDefinitions = null; LastInsertId = 0; RecordsAffected = 0; State = ResultSetState.None; m_dataLengths = null; m_dataOffsets = null; m_readBuffer.Clear(); m_row = null; m_rowBuffered = null; try { while (true) { var payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); var firstByte = payload.HeaderByte; if (firstByte == OkPayload.Signature) { var ok = OkPayload.Create(payload); RecordsAffected += ok.AffectedRowCount; LastInsertId = ok.LastInsertId; ColumnDefinitions = null; State = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; if (State == ResultSetState.NoMoreData) { break; } } else if (firstByte == LocalInfilePayload.Signature) { try { var localInfile = LocalInfilePayload.Create(payload); using (var stream = localInfile.FileName.StartsWith(MySqlBulkLoader.StreamPrefix, StringComparison.Ordinal) ? MySqlBulkLoader.GetAndRemoveStream(localInfile.FileName) : File.OpenRead(localInfile.FileName)) { byte[] readBuffer = new byte[65536]; int byteCount; while ((byteCount = await stream.ReadAsync(readBuffer, 0, readBuffer.Length).ConfigureAwait(false)) > 0) { payload = new PayloadData(new ArraySegment <byte>(readBuffer, 0, byteCount)); await Session.SendReplyAsync(payload, ioBehavior, CancellationToken.None).ConfigureAwait(false); } } } catch (Exception ex) { // store the exception, to be thrown after reading the response packet from the server ReadResultSetHeaderException = new MySqlException("Error during LOAD DATA LOCAL INFILE", ex); } await Session.SendReplyAsync(EmptyPayload.Create(), ioBehavior, CancellationToken.None).ConfigureAwait(false); } else { var reader = new ByteArrayReader(payload.ArraySegment); var columnCount = (int)reader.ReadLengthEncodedInteger(); ColumnDefinitions = new ColumnDefinitionPayload[columnCount]; m_dataOffsets = new int[columnCount]; m_dataLengths = new int[columnCount]; for (var column = 0; column < ColumnDefinitions.Length; column++) { payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); ColumnDefinitions[column] = ColumnDefinitionPayload.Create(payload); } payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); EofPayload.Create(payload); LastInsertId = -1; State = ResultSetState.ReadResultSetHeader; break; } } } catch (Exception ex) { ReadResultSetHeaderException = ex; } finally { BufferState = State; } return(this); }