<commit_before>﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Utilities;
using MySql.Data.MySqlClient;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore.Storage.Internal
{
    public class MySqlRelationalCommand : RelationalCommand
    {
        public MySqlRelationalCommand(
            [NotNull] ISensitiveDataLogger logger,
            [NotNull] DiagnosticSource diagnosticSource,
            [NotNull] string commandText,
            [NotNull] IReadOnlyList<IRelationalParameter> parameters)
            : base(logger, diagnosticSource, commandText, parameters)
        {
        }

	    protected override object Execute(
		    IRelationalConnection connection,
		    string executeMethod,
		    IReadOnlyDictionary<string, object> parameterValues,
		    bool closeConnection = true)
	    {
		    return ExecuteAsync(IOBehavior.Synchronous, connection, executeMethod, parameterValues, closeConnection)
			    .GetAwaiter()
			    .GetResult();
	    }

	    protected override async Task<object> ExecuteAsync(
		    IRelationalConnection connection,
		    string executeMethod,
		    IReadOnlyDictionary<string, object> parameterValues,
		    bool closeConnection = true,
		    CancellationToken cancellationToken = default(CancellationToken))
	    {
		    return await ExecuteAsync(IOBehavior.Asynchronous, connection, executeMethod, parameterValues, closeConnection, cancellationToken).ConfigureAwait(false);
	    }

	    private async Task<object> ExecuteAsync(
		    IOBehavior ioBehavior,
		    [NotNull] IRelationalConnection connection,
		    [NotNull] string executeMethod,
		    [CanBeNull] IReadOnlyDictionary<string, object> parameterValues,
		    bool closeConnection,
		    CancellationToken cancellationToken = default(CancellationToken))
	    {
            Check.NotNull(connection, nameof(connection));
            Check.NotEmpty(executeMethod, nameof(executeMethod));
            var dbCommand = CreateCommand(connection, parameterValues);
            object result;

            cancellationToken.ThrowIfCancellationRequested();
            var mySqlConnection = connection as MySqlRelationalConnection;
            var locked = false;
		    var startTimestamp = Stopwatch.GetTimestamp();

		    try
            {
	            if (ioBehavior == IOBehavior.Asynchronous)
	            {
		            // ReSharper disable once PossibleNullReferenceException
		            await mySqlConnection.PoolingOpenAsync(cancellationToken).ConfigureAwait(false);
		            await mySqlConnection.Lock.WaitAsync(cancellationToken).ConfigureAwait(false);
	            }
	            else
	            {
		            // ReSharper disable once PossibleNullReferenceException
		            mySqlConnection.PoolingOpen();
		            mySqlConnection.Lock.Wait(cancellationToken);
	            }
	            locked = true;
                switch (executeMethod)
                {
                    case nameof(ExecuteNonQuery):
                    {
                        using (dbCommand)
                        {
	                        if (ioBehavior == IOBehavior.Asynchronous)
		                        result = await dbCommand.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
	                        else
		                        result = dbCommand.ExecuteNonQuery();
                        }
                        break;
                    }
                    case nameof(ExecuteScalar):
                    {
                        using (dbCommand)
                        {
	                        if (ioBehavior == IOBehavior.Asynchronous)
		                        result = await dbCommand.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
	                        else
		                        result = dbCommand.ExecuteScalar();
                        }
                        break;
                    }
                    case nameof(ExecuteReader):
                    {
                        try
                        {
	                        MySqlDataReader dataReader;
	                        if (ioBehavior == IOBehavior.Asynchronous)
		                        dataReader = await dbCommand.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false) as MySqlDataReader;
	                        else
		                        dataReader = dbCommand.ExecuteReader() as MySqlDataReader;

	                        result = new RelationalDataReader(connection, dbCommand, new SynchronizedMySqlDataReader(dataReader, mySqlConnection));
                        }
                        catch (Exception)
                        {
                            dbCommand.Dispose();
                            throw;
                        }
                        break;
                    }
                    default:
                    {
                        throw new NotSupportedException();
                    }
                }
            }
            finally
            {
	            var currentTimestamp = Stopwatch.GetTimestamp();
	            Logger.LogCommandExecuted(dbCommand, startTimestamp, currentTimestamp);
	            if (locked && executeMethod != nameof(ExecuteReader))
                {
                    // if calling any other method, the command has finished executing and the lock can be released immediately
	                // ReSharper disable once PossibleNullReferenceException
	                mySqlConnection.Lock.Release();
	                mySqlConnection.PoolingClose();
                }
	            // ReSharper disable once PossibleNullReferenceException
	            if (!mySqlConnection.Pooling && closeConnection)
	            {
		            connection.Close();
	            }
            }
            return result;
        }

        private DbCommand CreateCommand(
            IRelationalConnection connection,
            IReadOnlyDictionary<string, object> parameterValues)
        {
            var command = connection.DbConnection.CreateCommand();

            command.CommandText = CommandText;
<commit_msg>fix logging and CI<commit_after>﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Utilities;
using MySql.Data.MySqlClient;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore.Storage.Internal
{
    public class MySqlRelationalCommand : RelationalCommand
    {
        public MySqlRelationalCommand(
            [NotNull] ISensitiveDataLogger logger,
            [NotNull] DiagnosticSource diagnosticSource,
            [NotNull] string commandText,
            [NotNull] IReadOnlyList<IRelationalParameter> parameters)
            : base(logger, diagnosticSource, commandText, parameters)
        {
        }

	    protected override object Execute(
		    IRelationalConnection connection,
		    string executeMethod,
		    IReadOnlyDictionary<string, object> parameterValues,
		    bool closeConnection = true)
	    {
		    return ExecuteAsync(IOBehavior.Synchronous, connection, executeMethod, parameterValues, closeConnection)
			    .GetAwaiter()
			    .GetResult();
	    }

	    protected override async Task<object> ExecuteAsync(
		    IRelationalConnection connection,
		    string executeMethod,
		    IReadOnlyDictionary<string, object> parameterValues,
		    bool closeConnection = true,
		    CancellationToken cancellationToken = default(CancellationToken))
	    {
		    return await ExecuteAsync(IOBehavior.Asynchronous, connection, executeMethod, parameterValues, closeConnection, cancellationToken).ConfigureAwait(false);
	    }

	    private async Task<object> ExecuteAsync(
		    IOBehavior ioBehavior,
		    [NotNull] IRelationalConnection connection,
		    [NotNull] string executeMethod,
		    [CanBeNull] IReadOnlyDictionary<string, object> parameterValues,
		    bool closeConnection,
		    CancellationToken cancellationToken = default(CancellationToken))
	    {
            Check.NotNull(connection, nameof(connection));
            Check.NotEmpty(executeMethod, nameof(executeMethod));
            var dbCommand = CreateCommand(connection, parameterValues);
            object result;

            cancellationToken.ThrowIfCancellationRequested();
            var mySqlConnection = connection as MySqlRelationalConnection;
            var locked = false;
		    var isReader = false;
		    var startTimestamp = Stopwatch.GetTimestamp();

		    try
            {
	            if (ioBehavior == IOBehavior.Asynchronous)
	            {
		            // ReSharper disable once PossibleNullReferenceException
		            await mySqlConnection.PoolingOpenAsync(cancellationToken).ConfigureAwait(false);
		            await mySqlConnection.Lock.WaitAsync(cancellationToken).ConfigureAwait(false);
	            }
	            else
	            {
		            // ReSharper disable once PossibleNullReferenceException
		            mySqlConnection.PoolingOpen();
		            mySqlConnection.Lock.Wait(cancellationToken);
	            }
	            locked = true;
                switch (executeMethod)
                {
                    case nameof(ExecuteNonQuery):
                    {
						if (ioBehavior == IOBehavior.Asynchronous)
							result = await dbCommand.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
						else
							result = dbCommand.ExecuteNonQuery();
	                    break;
                    }
                    case nameof(ExecuteScalar):
                    {
						if (ioBehavior == IOBehavior.Asynchronous)
							result = await dbCommand.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
						else
							result = dbCommand.ExecuteScalar();
	                    break;
                    }
                    case nameof(ExecuteReader):
                    {
						MySqlDataReader dataReader;
						if (ioBehavior == IOBehavior.Asynchronous)
							dataReader = await dbCommand.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false) as MySqlDataReader;
						else
							dataReader = dbCommand.ExecuteReader() as MySqlDataReader;
						result = new RelationalDataReader(connection, dbCommand, new SynchronizedMySqlDataReader(dataReader, mySqlConnection));
	                    isReader = true;
	                    break;
                    }
                    default:
                    {
                        throw new NotSupportedException();
                    }
                }
            }
            finally
            {
	            var currentTimestamp = Stopwatch.GetTimestamp();
	            Logger.LogCommandExecuted(dbCommand, startTimestamp, currentTimestamp);
	            if (!isReader)
	            {
					// NonQuery, Scalar, and Exceptions can be disposed, and should release locks
		            dbCommand.Dispose();
		            if (locked)
		            {
			            mySqlConnection.Lock.Release();
			            mySqlConnection.PoolingClose();
		            }
	            }
	            // ReSharper disable once PossibleNullReferenceException
	            if (!mySqlConnection.Pooling && closeConnection)
	            {
		            connection.Close();
	            }
            }
            return result;
        }

        private DbCommand CreateCommand(
            IRelationalConnection connection,
            IReadOnlyDictionary<string, object> parameterValues)
        {
            var command = connection.DbConnection.CreateCommand();

            command.CommandText = CommandText;

{'fraction_non_alphanumeric': 0.06452150716905636, 'fraction_numerical': 0.0, 'mean_word_length': 1.8611972334843787, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3319326', 'n_tokens_mistral': 2911, 'n_tokens_neox': 2593, 'n_words': 556}