private async Task GetRealServerDetailsAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) { try { await SendAsync(QueryPayload.Create("SELECT CONNECTION_ID(), VERSION();"), ioBehavior, cancellationToken).ConfigureAwait(false); // column count: 2 await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); // CONNECTION_ID() and VERSION() columns await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); PayloadData payload; if (!SupportsDeprecateEof) { payload = await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); EofPayload.Create(payload); } // first (and only) row int? connectionId = default; string serverVersion = null; payload = await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); var reader = new ByteArrayReader(payload.ArraySegment); var length = reader.ReadLengthEncodedIntegerOrNull(); if (length != -1) { connectionId = int.Parse(Encoding.UTF8.GetString(reader.ReadByteString(length)), CultureInfo.InvariantCulture); } length = reader.ReadLengthEncodedIntegerOrNull(); if (length != -1) { serverVersion = Encoding.UTF8.GetString(reader.ReadByteString(length)); } // OK/EOF payload payload = await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false); if (OkPayload.IsOk(payload, SupportsDeprecateEof)) { OkPayload.Create(payload, SupportsDeprecateEof); } else { EofPayload.Create(payload); } if (connectionId.HasValue && serverVersion != null) { ConnectionId = connectionId.Value; ServerVersion = new ServerVersion(serverVersion); } } catch (MySqlException) { } }
private Row ScanRowAsyncRemainder(Row row, PayloadData payload) { if (EofPayload.IsEof(payload)) { var eof = EofPayload.Create(payload); BufferState = (eof.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; m_rowBuffered = null; return(null); } var reader = new ByteArrayReader(payload.ArraySegment); for (var column = 0; column < m_dataOffsets.Length; column++) { var length = checked ((int)ReadFieldLength(reader)); m_dataLengths[column] = length == -1 ? 0 : length; m_dataOffsets[column] = length == -1 ? -1 : reader.Offset; reader.Offset += m_dataLengths[column]; } if (row == null) { row = new Row(this); } row.SetData(m_dataLengths, m_dataOffsets, payload.ArraySegment.Array); m_rowBuffered = row; return(row); }
private ValueTask <Row> ScanRowAsync(IOBehavior ioBehavior, Row row, CancellationToken cancellationToken) { // if we've already read past the end of this resultset, Read returns false if (BufferState == ResultSetState.HasMoreData || BufferState == ResultSetState.NoMoreData || BufferState == ResultSetState.None) { return(new ValueTask <Row>((Row)null)); } using (Command.RegisterCancel(cancellationToken)) { var payloadValueTask = Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None); return(payloadValueTask.IsCompletedSuccessfully ? new ValueTask <Row>(ScanRowAsyncRemainder(payloadValueTask.Result)) : new ValueTask <Row>(ScanRowAsyncAwaited(payloadValueTask.AsTask(), cancellationToken))); } async Task <Row> ScanRowAsyncAwaited(Task <PayloadData> payloadTask, CancellationToken token) { try { return(ScanRowAsyncRemainder(await payloadTask.ConfigureAwait(false))); } catch (MySqlException ex) when(ex.Number == (int)MySqlErrorCode.QueryInterrupted) { BufferState = State = ResultSetState.NoMoreData; token.ThrowIfCancellationRequested(); throw; } } Row ScanRowAsyncRemainder(PayloadData payload) { if (EofPayload.IsEof(payload)) { var eof = EofPayload.Create(payload); BufferState = (eof.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; m_rowBuffered = null; return(null); } var reader = new ByteArrayReader(payload.ArraySegment); for (var column = 0; column < m_dataOffsets.Length; column++) { var length = reader.ReadLengthEncodedIntegerOrNull(); m_dataLengths[column] = length == -1 ? 0 : length; m_dataOffsets[column] = length == -1 ? -1 : reader.Offset; reader.Offset += m_dataLengths[column]; } if (row == null) { row = new Row(this); } row.SetData(m_dataLengths, m_dataOffsets, payload.ArraySegment); m_rowBuffered = row; return(row); } }
private async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) { while (true) { var payload = await m_session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); var firstByte = payload.HeaderByte; if (firstByte == OkPayload.Signature) { var ok = OkPayload.Create(payload); m_recordsAffected += ok.AffectedRowCount; m_command.LastInsertedId = ok.LastInsertId; m_columnDefinitions = null; m_state = ok.ServerStatus.HasFlag(ServerStatus.MoreResultsExist) ? State.HasMoreData : State.NoMoreData; if (m_state == State.NoMoreData) { break; } } else if (firstByte == 0xFB) { throw new NotSupportedException("Don't support LOCAL_INFILE_Request"); } else { var reader = new ByteArrayReader(payload.ArraySegment); var columnCount = (int)reader.ReadLengthEncodedInteger(); m_columnDefinitions = new ColumnDefinitionPayload[columnCount]; m_dataOffsets = new int[columnCount]; m_dataLengths = new int[columnCount]; for (var column = 0; column < m_columnDefinitions.Length; column++) { payload = await m_session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); m_columnDefinitions[column] = ColumnDefinitionPayload.Create(payload); } payload = await m_session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); EofPayload.Create(payload); m_command.LastInsertedId = -1; m_state = State.ReadResultSetHeader; break; } } }
private bool ReadAsyncRemainder(PayloadData payload) { if (EofPayload.IsEof(payload)) { var eof = EofPayload.Create(payload); m_state = eof.ServerStatus.HasFlag(ServerStatus.MoreResultsExist) ? State.HasMoreData : State.NoMoreData; return(false); } var reader = new ByteArrayReader(payload.ArraySegment); for (var column = 0; column < m_dataOffsets.Length; column++) { var length = checked ((int)ReadFieldLength(reader)); m_dataLengths[column] = length == -1 ? 0 : length; m_dataOffsets[column] = length == -1 ? -1 : reader.Offset; reader.Offset += m_dataLengths[column]; } m_currentRow = payload.ArraySegment.Array; m_state = State.ReadingRows; return(true); }
public async Task <ResultSet> ReadResultSetHeaderAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) { // 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; while (true) { var payload = await Session.ReceiveReplyAsync(ioBehavior, cancellationToken).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 == 0xFB) { throw new NotSupportedException("Don't support LOCAL_INFILE_Request"); } 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).ConfigureAwait(false); ColumnDefinitions[column] = ColumnDefinitionPayload.Create(payload); } payload = await Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); EofPayload.Create(payload); LastInsertId = -1; State = ResultSetState.ReadResultSetHeader; break; } } 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; } }
static Row?ScanRowAsyncRemainder(ResultSet this_, PayloadData payload, Row?row_) { if (payload.HeaderByte == EofPayload.Signature) { var span = payload.Span; if (this_.Session.SupportsDeprecateEof && OkPayload.IsOk(span, this_.Session.SupportsDeprecateEof)) { var ok = OkPayload.Create(span, this_.Session.SupportsDeprecateEof, this_.Session.SupportsSessionTrack); this_.BufferState = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; return(null); } if (!this_.Session.SupportsDeprecateEof && EofPayload.IsEof(payload)) { var eof = EofPayload.Create(span); this_.BufferState = (eof.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; return(null); } } if (row_ is null) { bool isBinaryRow = false; if (payload.HeaderByte == 0 && !this_.Connection.IgnorePrepare) { // this might be a binary row, but it might also be a text row whose first column is zero bytes long; try reading // the row as a series of length-encoded values (the text format) to see if this might plausibly be a text row var isTextRow = false; var reader = new ByteArrayReader(payload.Span); var columnCount = 0; while (reader.BytesRemaining > 0) { int length; var firstByte = reader.ReadByte(); if (firstByte == 0xFB) { // NULL length = 0; } else if (firstByte == 0xFC) { // two-byte length-encoded integer if (reader.BytesRemaining < 2) { break; } length = unchecked ((int)reader.ReadFixedLengthUInt32(2)); } else if (firstByte == 0xFD) { // three-byte length-encoded integer if (reader.BytesRemaining < 3) { break; } length = unchecked ((int)reader.ReadFixedLengthUInt32(3)); } else if (firstByte == 0xFE) { // eight-byte length-encoded integer if (reader.BytesRemaining < 8) { break; } length = checked ((int)reader.ReadFixedLengthUInt64(8)); } else if (firstByte == 0xFF) { // invalid length prefix break; } else { // single-byte length length = firstByte; } if (reader.BytesRemaining < length) { break; } reader.Offset += length; columnCount++; if (columnCount == this_.ColumnDefinitions !.Length) { // if we used up all the bytes reading exactly 'ColumnDefinitions' length-encoded columns, then assume this is a text row if (reader.BytesRemaining == 0) { isTextRow = true; } break; } } isBinaryRow = !isTextRow; } row_ = isBinaryRow ? (Row) new BinaryRow(this_) : new TextRow(this_); } row_.SetData(payload.Memory); this_.m_hasRows = true; this_.BufferState = ResultSetState.ReadingRows; return(row_); }
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); }
private async Task DoPrepareAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) { var statementPreparer = new StatementPreparer(CommandText, m_parameterCollection, CreateStatementPreparerOptions()); var parsedStatements = statementPreparer.SplitStatements(); if (parsedStatements.Statements.Count > 1) { throw new NotSupportedException("Multiple semicolon-delimited SQL statements are not supported by MySqlCommand.Prepare"); } var columnsAndParameters = new ResizableArray <byte>(); var columnsAndParametersSize = 0; var preparedStatements = new List <PreparedStatement>(parsedStatements.Statements.Count); foreach (var statement in parsedStatements.Statements) { await Connection.Session.SendAsync(new PayloadData(statement.StatementBytes), ioBehavior, cancellationToken).ConfigureAwait(false); var payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); var response = StatementPrepareResponsePayload.Create(payload.AsSpan()); ColumnDefinitionPayload[] parameters = null; if (response.ParameterCount > 0) { parameters = new ColumnDefinitionPayload[response.ParameterCount]; for (var i = 0; i < response.ParameterCount; i++) { payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); Utility.Resize(ref columnsAndParameters, columnsAndParametersSize + payload.ArraySegment.Count); Buffer.BlockCopy(payload.ArraySegment.Array, payload.ArraySegment.Offset, columnsAndParameters.Array, columnsAndParametersSize, payload.ArraySegment.Count); parameters[i] = ColumnDefinitionPayload.Create(new ResizableArraySegment <byte>(columnsAndParameters, columnsAndParametersSize, payload.ArraySegment.Count)); columnsAndParametersSize += payload.ArraySegment.Count; } if (!Connection.Session.SupportsDeprecateEof) { payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); EofPayload.Create(payload.AsSpan()); } } ColumnDefinitionPayload[] columns = null; if (response.ColumnCount > 0) { columns = new ColumnDefinitionPayload[response.ColumnCount]; for (var i = 0; i < response.ColumnCount; i++) { payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); Utility.Resize(ref columnsAndParameters, columnsAndParametersSize + payload.ArraySegment.Count); Buffer.BlockCopy(payload.ArraySegment.Array, payload.ArraySegment.Offset, columnsAndParameters.Array, columnsAndParametersSize, payload.ArraySegment.Count); columns[i] = ColumnDefinitionPayload.Create(new ResizableArraySegment <byte>(columnsAndParameters, columnsAndParametersSize, payload.ArraySegment.Count)); columnsAndParametersSize += payload.ArraySegment.Count; } if (!Connection.Session.SupportsDeprecateEof) { payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); EofPayload.Create(payload.AsSpan()); } } preparedStatements.Add(new PreparedStatement(response.StatementId, statement, columns, parameters)); } Connection.Session.AddPreparedStatement(CommandText, new PreparedStatements(preparedStatements, parsedStatements)); }
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); }
private ValueTask <Row> ScanRowAsync(IOBehavior ioBehavior, Row row, CancellationToken cancellationToken) { // if we've already read past the end of this resultset, Read returns false if (BufferState == ResultSetState.HasMoreData || BufferState == ResultSetState.NoMoreData || BufferState == ResultSetState.None) { return(new ValueTask <Row>((Row)null)); } using (Command.RegisterCancel(cancellationToken)) { var payloadValueTask = Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None); return(payloadValueTask.IsCompletedSuccessfully ? new ValueTask <Row>(ScanRowAsyncRemainder(payloadValueTask.Result, row)) : new ValueTask <Row>(ScanRowAsyncAwaited(payloadValueTask.AsTask(), row, cancellationToken))); } async Task <Row> ScanRowAsyncAwaited(Task <PayloadData> payloadTask, Row row_, CancellationToken token) { PayloadData payloadData; try { payloadData = await payloadTask.ConfigureAwait(false); } catch (MySqlException ex) { BufferState = State = ResultSetState.NoMoreData; if (ex.Number == (int)MySqlErrorCode.QueryInterrupted) { token.ThrowIfCancellationRequested(); } throw; } return(ScanRowAsyncRemainder(payloadData, row_)); } Row ScanRowAsyncRemainder(PayloadData payload, Row row_) { if (payload.HeaderByte == EofPayload.Signature) { var span = payload.AsSpan(); if (Session.SupportsDeprecateEof && OkPayload.IsOk(span, Session.SupportsDeprecateEof)) { var ok = OkPayload.Create(span, Session.SupportsDeprecateEof, Session.SupportsSessionTrack); BufferState = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; m_rowBuffered = null; return(null); } if (!Session.SupportsDeprecateEof && EofPayload.IsEof(payload)) { var eof = EofPayload.Create(span); BufferState = (eof.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; m_rowBuffered = null; return(null); } } if (row_ == null) { row_ = DataReader.ResultSetProtocol == ResultSetProtocol.Binary ? (Row) new BinaryRow(this) : new TextRow(this); } row_.SetData(payload.ArraySegment); m_rowBuffered = row_; m_hasRows = true; BufferState = ResultSetState.ReadingRows; return(row_); } }
private ValueTask <Row> ScanRowAsync(IOBehavior ioBehavior, Row row, CancellationToken cancellationToken) { // if we've already read past the end of this resultset, Read returns false if (BufferState == ResultSetState.HasMoreData || BufferState == ResultSetState.NoMoreData || BufferState == ResultSetState.None) { return(new ValueTask <Row>((Row)null)); } using (Command.CancellableCommand.RegisterCancel(cancellationToken)) { var payloadValueTask = Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None); return(payloadValueTask.IsCompletedSuccessfully ? new ValueTask <Row>(ScanRowAsyncRemainder(payloadValueTask.Result, row)) : new ValueTask <Row>(ScanRowAsyncAwaited(payloadValueTask.AsTask(), row, cancellationToken))); } async Task <Row> ScanRowAsyncAwaited(Task <PayloadData> payloadTask, Row row_, CancellationToken token) { PayloadData payloadData; try { payloadData = await payloadTask.ConfigureAwait(false); } catch (MySqlException ex) { BufferState = State = ResultSetState.NoMoreData; if (ex.Number == (int)MySqlErrorCode.QueryInterrupted) { token.ThrowIfCancellationRequested(); } throw; } return(ScanRowAsyncRemainder(payloadData, row_)); } Row ScanRowAsyncRemainder(PayloadData payload, Row row_) { if (payload.HeaderByte == EofPayload.Signature) { var span = payload.AsSpan(); if (Session.SupportsDeprecateEof && OkPayload.IsOk(span, Session.SupportsDeprecateEof)) { var ok = OkPayload.Create(span, Session.SupportsDeprecateEof, Session.SupportsSessionTrack); BufferState = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; m_rowBuffered = null; return(null); } if (!Session.SupportsDeprecateEof && EofPayload.IsEof(payload)) { var eof = EofPayload.Create(span); BufferState = (eof.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData; m_rowBuffered = null; return(null); } } if (row_ is null) { bool isBinaryRow = false; if (payload.HeaderByte == 0 && !Connection.IgnorePrepare) { // this might be a binary row, but it might also be a text row whose first column is zero bytes long; try reading // the row as a series of length-encoded values (the text format) to see if this might plausibly be a text row var isTextRow = false; var reader = new ByteArrayReader(payload.AsSpan()); var columnCount = 0; while (reader.BytesRemaining > 0) { int length; var firstByte = reader.ReadByte(); if (firstByte == 0xFB) { // NULL length = 0; } else if (firstByte == 0xFC) { // two-byte length-encoded integer if (reader.BytesRemaining < 2) { break; } length = unchecked ((int)reader.ReadFixedLengthUInt32(2)); } else if (firstByte == 0xFD) { // three-byte length-encoded integer if (reader.BytesRemaining < 3) { break; } length = unchecked ((int)reader.ReadFixedLengthUInt32(3)); } else if (firstByte == 0xFE) { // eight-byte length-encoded integer if (reader.BytesRemaining < 8) { break; } length = checked ((int)reader.ReadFixedLengthUInt64(8)); } else if (firstByte == 0xFF) { // invalid length prefix break; } else { // single-byte length length = firstByte; } if (reader.BytesRemaining < length) { break; } reader.Offset += length; columnCount++; if (columnCount == ColumnDefinitions.Length) { // if we used up all the bytes reading exactly 'ColumnDefinitions' length-encoded columns, then assume this is a text row if (reader.BytesRemaining == 0) { isTextRow = true; } break; } } isBinaryRow = !isTextRow; } row_ = isBinaryRow ? (Row) new BinaryRow(this) : new TextRow(this); } row_.SetData(payload.ArraySegment); m_rowBuffered = row_; m_hasRows = true; BufferState = ResultSetState.ReadingRows; return(row_); } }
private async Task PrepareAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) { if (Connection == null) { throw new InvalidOperationException("Connection property must be non-null."); } if (Connection.State != ConnectionState.Open) { throw new InvalidOperationException("Connection must be Open; current state is {0}".FormatInvariant(Connection.State)); } if (string.IsNullOrWhiteSpace(CommandText)) { throw new InvalidOperationException("CommandText must be specified"); } if (m_connection?.HasActiveReader ?? false) { throw new InvalidOperationException("Cannot call Prepare when there is an open DataReader for this command; it must be closed first."); } if (Connection.IgnorePrepare) { return; } if (CommandType != CommandType.Text) { throw new NotSupportedException("Only CommandType.Text is currently supported by MySqlCommand.Prepare"); } var statementPreparer = new StatementPreparer(CommandText, Parameters, CreateStatementPreparerOptions()); var parsedStatements = statementPreparer.SplitStatements(); if (parsedStatements.Statements.Count > 1) { throw new NotSupportedException("Multiple semicolon-delimited SQL statements are not supported by MySqlCommand.Prepare"); } var columnsAndParameters = new ResizableArray <byte>(); var columnsAndParametersSize = 0; var preparedStatements = new List <PreparedStatement>(parsedStatements.Statements.Count); foreach (var statement in parsedStatements.Statements) { await Connection.Session.SendAsync(new PayloadData(statement.StatementBytes), ioBehavior, cancellationToken).ConfigureAwait(false); var payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); var response = StatementPrepareResponsePayload.Create(payload); ColumnDefinitionPayload[] parameters = null; if (response.ParameterCount > 0) { parameters = new ColumnDefinitionPayload[response.ParameterCount]; for (var i = 0; i < response.ParameterCount; i++) { payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); Utility.Resize(ref columnsAndParameters, columnsAndParametersSize + payload.ArraySegment.Count); Buffer.BlockCopy(payload.ArraySegment.Array, payload.ArraySegment.Offset, columnsAndParameters.Array, columnsAndParametersSize, payload.ArraySegment.Count); parameters[i] = ColumnDefinitionPayload.Create(new ResizableArraySegment <byte>(columnsAndParameters, columnsAndParametersSize, payload.ArraySegment.Count)); columnsAndParametersSize += payload.ArraySegment.Count; } if (!Connection.Session.SupportsDeprecateEof) { payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); EofPayload.Create(payload); } } ColumnDefinitionPayload[] columns = null; if (response.ColumnCount > 0) { columns = new ColumnDefinitionPayload[response.ColumnCount]; for (var i = 0; i < response.ColumnCount; i++) { payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); Utility.Resize(ref columnsAndParameters, columnsAndParametersSize + payload.ArraySegment.Count); Buffer.BlockCopy(payload.ArraySegment.Array, payload.ArraySegment.Offset, columnsAndParameters.Array, columnsAndParametersSize, payload.ArraySegment.Count); columns[i] = ColumnDefinitionPayload.Create(new ResizableArraySegment <byte>(columnsAndParameters, columnsAndParametersSize, payload.ArraySegment.Count)); columnsAndParametersSize += payload.ArraySegment.Count; } if (!Connection.Session.SupportsDeprecateEof) { payload = await Connection.Session.ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false); EofPayload.Create(payload); } } preparedStatements.Add(new PreparedStatement(response.StatementId, statement, columns, parameters)); } m_parsedStatements = parsedStatements; m_statements = preparedStatements; }