internal MySqlDbColumn(int ordinal, ColumnDefinitionPayload column, Type type, string dataTypeName) { var columnSize = type == typeof(string) || type == typeof(Guid) ? column.ColumnLength / SerializationUtility.GetBytesPerCharacter(column.CharacterSet) : column.ColumnLength; AllowDBNull = (column.ColumnFlags & ColumnFlags.NotNull) == 0; BaseCatalogName = null; BaseColumnName = column.PhysicalName; BaseSchemaName = column.SchemaName; BaseTableName = column.PhysicalTable; ColumnName = column.Name; ColumnOrdinal = ordinal; ColumnSize = columnSize > int.MaxValue ? int.MaxValue : unchecked ((int)columnSize); DataType = type; DataTypeName = dataTypeName; IsAliased = column.PhysicalName != column.Name; IsAutoIncrement = (column.ColumnFlags & ColumnFlags.AutoIncrement) != 0; IsExpression = false; IsHidden = false; IsKey = (column.ColumnFlags & ColumnFlags.PrimaryKey) != 0; IsLong = column.ColumnLength > 255 && ((column.ColumnFlags & ColumnFlags.Blob) != 0 || column.ColumnType == ColumnType.TinyBlob || column.ColumnType == ColumnType.Blob || column.ColumnType == ColumnType.MediumBlob || column.ColumnType == ColumnType.LongBlob); IsReadOnly = false; IsUnique = (column.ColumnFlags & ColumnFlags.UniqueKey) != 0; if (column.ColumnType == ColumnType.Decimal || column.ColumnType == ColumnType.NewDecimal) { NumericPrecision = (int)(column.ColumnLength - 2 + ((column.ColumnFlags & ColumnFlags.Unsigned) != 0 ? 1 : 0)); } NumericScale = column.Decimals; ProviderType = (int)column.ColumnType; }
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; } } }
internal MySqlDbColumn(int ordinal, ColumnDefinitionPayload column, MySqlDbType mySqlDbType) { var columnTypeMetadata = TypeMapper.Instance.GetColumnTypeMetadata(mySqlDbType); var type = columnTypeMetadata.DbTypeMapping.ClrType; var columnSize = type == typeof(string) || type == typeof(Guid) ? column.ColumnLength / ProtocolUtility.GetBytesPerCharacter(column.CharacterSet) : column.ColumnLength; AllowDBNull = (column.ColumnFlags & ColumnFlags.NotNull) == 0; BaseCatalogName = null; BaseColumnName = column.PhysicalName; BaseSchemaName = column.SchemaName; BaseTableName = column.PhysicalTable; ColumnName = column.Name; ColumnOrdinal = ordinal; ColumnSize = columnSize > int.MaxValue ? int.MaxValue : unchecked ((int)columnSize); DataType = type; DataTypeName = columnTypeMetadata.SimpleDataTypeName; if (mySqlDbType == MySqlDbType.String) { DataTypeName += string.Format(CultureInfo.InvariantCulture, "({0})", columnSize); } IsAliased = column.PhysicalName != column.Name; IsAutoIncrement = (column.ColumnFlags & ColumnFlags.AutoIncrement) != 0; IsExpression = false; IsHidden = false; IsKey = (column.ColumnFlags & ColumnFlags.PrimaryKey) != 0; IsLong = column.ColumnLength > 255 && ((column.ColumnFlags & ColumnFlags.Blob) != 0 || column.ColumnType == ColumnType.TinyBlob || column.ColumnType == ColumnType.Blob || column.ColumnType == ColumnType.MediumBlob || column.ColumnType == ColumnType.LongBlob); IsReadOnly = false; IsUnique = (column.ColumnFlags & ColumnFlags.UniqueKey) != 0; if (column.ColumnType == ColumnType.Decimal || column.ColumnType == ColumnType.NewDecimal) { NumericPrecision = (int)column.ColumnLength; if ((column.ColumnFlags & ColumnFlags.Unsigned) == 0) { NumericPrecision--; } if (column.Decimals > 0) { NumericPrecision--; } } NumericScale = column.Decimals; ProviderType = mySqlDbType; }
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; } }
public static MySqlDbType ConvertToMySqlDbType(ColumnDefinitionPayload columnDefinition, bool treatTinyAsBoolean, MySqlGuidFormat guidFormat) { var isUnsigned = (columnDefinition.ColumnFlags & ColumnFlags.Unsigned) != 0; switch (columnDefinition.ColumnType) { case ColumnType.Tiny: return(treatTinyAsBoolean && columnDefinition.ColumnLength == 1 ? MySqlDbType.Bool : isUnsigned?MySqlDbType.UByte : MySqlDbType.Byte); case ColumnType.Int24: return(isUnsigned ? MySqlDbType.UInt24 : MySqlDbType.Int24); case ColumnType.Long: return(isUnsigned ? MySqlDbType.UInt32 : MySqlDbType.Int32); case ColumnType.Longlong: return(isUnsigned ? MySqlDbType.UInt64 : MySqlDbType.Int64); case ColumnType.Bit: return(MySqlDbType.Bit); case ColumnType.String: if (guidFormat == MySqlGuidFormat.Char36 && columnDefinition.ColumnLength / ProtocolUtility.GetBytesPerCharacter(columnDefinition.CharacterSet) == 36) { return(MySqlDbType.Guid); } if (guidFormat == MySqlGuidFormat.Char32 && columnDefinition.ColumnLength / ProtocolUtility.GetBytesPerCharacter(columnDefinition.CharacterSet) == 32) { return(MySqlDbType.Guid); } if ((columnDefinition.ColumnFlags & ColumnFlags.Enum) != 0) { return(MySqlDbType.Enum); } if ((columnDefinition.ColumnFlags & ColumnFlags.Set) != 0) { return(MySqlDbType.Set); } goto case ColumnType.VarString; case ColumnType.VarString: case ColumnType.TinyBlob: case ColumnType.Blob: case ColumnType.MediumBlob: case ColumnType.LongBlob: var type = columnDefinition.ColumnType; if (columnDefinition.CharacterSet == CharacterSet.Binary) { if ((guidFormat == MySqlGuidFormat.Binary16 || guidFormat == MySqlGuidFormat.TimeSwapBinary16 || guidFormat == MySqlGuidFormat.LittleEndianBinary16) && columnDefinition.ColumnLength == 16) { return(MySqlDbType.Guid); } return(type == ColumnType.String ? MySqlDbType.Binary : type == ColumnType.VarString ? MySqlDbType.VarBinary : type == ColumnType.TinyBlob ? MySqlDbType.TinyBlob : type == ColumnType.Blob ? MySqlDbType.Blob : type == ColumnType.MediumBlob ? MySqlDbType.MediumBlob : MySqlDbType.LongBlob); } return(type == ColumnType.String ? MySqlDbType.String : type == ColumnType.VarString ? MySqlDbType.VarChar : type == ColumnType.TinyBlob ? MySqlDbType.TinyText : type == ColumnType.Blob ? MySqlDbType.Text : type == ColumnType.MediumBlob ? MySqlDbType.MediumText : MySqlDbType.LongText); case ColumnType.Json: return(MySqlDbType.JSON); case ColumnType.Short: return(isUnsigned ? MySqlDbType.UInt16 : MySqlDbType.Int16); case ColumnType.Date: return(MySqlDbType.Date); case ColumnType.DateTime: return(MySqlDbType.DateTime); case ColumnType.Timestamp: return(MySqlDbType.Timestamp); case ColumnType.Time: return(MySqlDbType.Time); case ColumnType.Year: return(MySqlDbType.Year); case ColumnType.Float: return(MySqlDbType.Float); case ColumnType.Double: return(MySqlDbType.Double); case ColumnType.Decimal: return(MySqlDbType.Decimal); case ColumnType.NewDecimal: return(MySqlDbType.NewDecimal); case ColumnType.Geometry: return(MySqlDbType.Geometry); case ColumnType.Null: return(MySqlDbType.Null); default: throw new NotImplementedException("ConvertToMySqlDbType for {0} is not implemented".FormatInvariant(columnDefinition.ColumnType)); } }
protected override int GetInt32Core(ReadOnlySpan <byte> data, ColumnDefinitionPayload columnDefinition) => !Utf8Parser.TryParse(data, out int value, out var bytesConsumed) || bytesConsumed != data.Length ? throw new OverflowException() : value;
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); }
protected override object GetValueCore(ReadOnlySpan <byte> data, ColumnDefinitionPayload columnDefinition) { var isUnsigned = (columnDefinition.ColumnFlags & ColumnFlags.Unsigned) != 0; switch (columnDefinition.ColumnType) { case ColumnType.Tiny: var value = ParseInt32(data); if (Connection.TreatTinyAsBoolean && columnDefinition.ColumnLength == 1 && !isUnsigned) { return(value != 0); } return(isUnsigned ? (object)(byte)value : (sbyte)value); case ColumnType.Int24: case ColumnType.Long: return(isUnsigned ? (object)ParseUInt32(data) : ParseInt32(data)); case ColumnType.Longlong: return(isUnsigned ? (object)ParseUInt64(data) : ParseInt64(data)); case ColumnType.Bit: return(ReadBit(data, columnDefinition)); case ColumnType.String: if (Connection.GuidFormat == MySqlGuidFormat.Char36 && columnDefinition.ColumnLength / ProtocolUtility.GetBytesPerCharacter(columnDefinition.CharacterSet) == 36) { return(Utf8Parser.TryParse(data, out Guid guid, out int guid36BytesConsumed, 'D') && guid36BytesConsumed == 36 ? guid : throw new FormatException()); } if (Connection.GuidFormat == MySqlGuidFormat.Char32 && columnDefinition.ColumnLength / ProtocolUtility.GetBytesPerCharacter(columnDefinition.CharacterSet) == 32) { return(Utf8Parser.TryParse(data, out Guid guid, out int guid32BytesConsumed, 'N') && guid32BytesConsumed == 32 ? guid : throw new FormatException()); } goto case ColumnType.VarString; case ColumnType.VarString: case ColumnType.VarChar: case ColumnType.TinyBlob: case ColumnType.Blob: case ColumnType.MediumBlob: case ColumnType.LongBlob: if (columnDefinition.CharacterSet == CharacterSet.Binary) { var guidFormat = Connection.GuidFormat; if ((guidFormat == MySqlGuidFormat.Binary16 || guidFormat == MySqlGuidFormat.TimeSwapBinary16 || guidFormat == MySqlGuidFormat.LittleEndianBinary16) && columnDefinition.ColumnLength == 16) { return(CreateGuidFromBytes(guidFormat, data)); } return(data.ToArray()); } return(Encoding.UTF8.GetString(data)); case ColumnType.Json: return(Encoding.UTF8.GetString(data)); case ColumnType.Short: return(isUnsigned ? (object)ParseUInt16(data) : ParseInt16(data)); case ColumnType.Date: case ColumnType.DateTime: case ColumnType.Timestamp: return(ParseDateTime(data)); case ColumnType.Time: return(Utility.ParseTimeSpan(data)); case ColumnType.Year: return(ParseInt32(data)); case ColumnType.Float: return(!Utf8Parser.TryParse(data, out float floatValue, out var floatBytesConsumed) || floatBytesConsumed != data.Length ? throw new FormatException() : floatValue); case ColumnType.Double: return(!Utf8Parser.TryParse(data, out double doubleValue, out var doubleBytesConsumed) || doubleBytesConsumed != data.Length ? throw new FormatException() : doubleValue); case ColumnType.Decimal: case ColumnType.NewDecimal: return(Utf8Parser.TryParse(data, out decimal decimalValue, out int bytesConsumed) && bytesConsumed == data.Length ? decimalValue : throw new FormatException()); case ColumnType.Geometry: return(data.ToArray()); default: throw new NotImplementedException("Reading {0} not implemented".FormatInvariant(columnDefinition.ColumnType)); } }
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 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; }
protected override object GetValueCore(ReadOnlySpan <byte> data, ColumnDefinitionPayload columnDefinition) { var isUnsigned = (columnDefinition.ColumnFlags & ColumnFlags.Unsigned) != 0; switch (columnDefinition.ColumnType) { case ColumnType.Tiny: if (Connection.TreatTinyAsBoolean && columnDefinition.ColumnLength == 1 && !isUnsigned) { return(data[0] != 0); } return(isUnsigned ? (object)data[0] : (sbyte)data[0]); case ColumnType.Int24: case ColumnType.Long: return(isUnsigned ? (object)MemoryMarshal.Read <uint>(data) : MemoryMarshal.Read <int>(data)); case ColumnType.Longlong: return(isUnsigned ? (object)MemoryMarshal.Read <ulong>(data) : MemoryMarshal.Read <long>(data)); case ColumnType.Bit: // BIT column is transmitted as MSB byte array ulong bitValue = 0; for (int i = 0; i < data.Length; i++) { bitValue = bitValue * 256 + data[i]; } return(bitValue); case ColumnType.String: if (Connection.GuidFormat == MySqlGuidFormat.Char36 && columnDefinition.ColumnLength / ProtocolUtility.GetBytesPerCharacter(columnDefinition.CharacterSet) == 36) { return(Utf8Parser.TryParse(data, out Guid guid, out int guid36BytesConsumed, 'D') && guid36BytesConsumed == 36 ? guid : throw new FormatException()); } if (Connection.GuidFormat == MySqlGuidFormat.Char32 && columnDefinition.ColumnLength / ProtocolUtility.GetBytesPerCharacter(columnDefinition.CharacterSet) == 32) { return(Utf8Parser.TryParse(data, out Guid guid, out int guid32BytesConsumed, 'N') && guid32BytesConsumed == 32 ? guid : throw new FormatException()); } goto case ColumnType.VarString; case ColumnType.VarString: case ColumnType.VarChar: case ColumnType.TinyBlob: case ColumnType.Blob: case ColumnType.MediumBlob: case ColumnType.LongBlob: if (columnDefinition.CharacterSet == CharacterSet.Binary) { var guidFormat = Connection.GuidFormat; if ((guidFormat == MySqlGuidFormat.Binary16 || guidFormat == MySqlGuidFormat.TimeSwapBinary16 || guidFormat == MySqlGuidFormat.LittleEndianBinary16) && columnDefinition.ColumnLength == 16) { return(CreateGuidFromBytes(guidFormat, data)); } return(data.ToArray()); } return(Encoding.UTF8.GetString(data)); case ColumnType.Json: return(Encoding.UTF8.GetString(data)); case ColumnType.Short: return(isUnsigned ? (object)MemoryMarshal.Read <ushort>(data) : MemoryMarshal.Read <short>(data)); case ColumnType.Date: case ColumnType.DateTime: case ColumnType.Timestamp: return(ReadDateTime(data)); case ColumnType.Time: return(ReadTimeSpan(data)); case ColumnType.Year: return((int)MemoryMarshal.Read <short>(data)); case ColumnType.Float: return(MemoryMarshal.Read <float>(data)); case ColumnType.Double: return(MemoryMarshal.Read <double>(data)); case ColumnType.Decimal: case ColumnType.NewDecimal: return(Utf8Parser.TryParse(data, out decimal decimalValue, out int bytesConsumed) && bytesConsumed == data.Length ? decimalValue : throw new FormatException()); case ColumnType.Geometry: return(data.ToArray()); default: throw new NotImplementedException("Reading {0} not implemented".FormatInvariant(columnDefinition.ColumnType)); } }