/// <summary>
        /// Execute server-side AnalyzeBatch procedure
        /// </summary>
        public async Task <AnalyzerStatistics> AnalyzeBatchAsync(string connectionStringBatch, string statement, ClearCacheMode clearCacheMode = ClearCacheMode.Default, string xconfig = null, string batchName = null, bool throwOnError = true)
        {
            #region Argument exception

            if (connectionStringBatch == null)
            {
                throw new ArgumentNullException("connectionStringBatch");
            }

            if (statement == null)
            {
                throw new ArgumentNullException("statement");
            }

            #endregion

            var currentProcess = Process.GetCurrentProcess();
            var processName    = currentProcess.ProcessName;
            var clientVersion  = "{0} ({1})".FormatWith(currentProcess.MainModule.FileVersionInfo.FileVersion, ClientVersion);

#if DEBUG
            Func <Guid, ClearCacheMode, string> commandAnalyze = (batchID, cacheMode) => "call {0}.AnalyzeBatchWithDebug(\"{1}\", {2}, \"{3}\", \"{4}\", \"{5}\", \"{6}\", \"{7}\", \"{8}\");".FormatWith(ClrAssemblyID, statement.EscapeMdxString(), (int)cacheMode, batchID, connectionStringBatch.EscapeMdxString(), clientVersion, processName, batchName, throwOnError);
#else
            Func <Guid, ClearCacheMode, string> commandAnalyze = (batchID, cacheMode) => "call {0}.AnalyzeBatch(\"{1}\", {2}, \"{3}\", \"{4}\", \"{5}\", \"{6}\", \"{7}\", \"{8}\");".FormatWith(ClrAssemblyID, statement.EscapeMdxString(), (int)cacheMode, batchID, connectionStringBatch.EscapeMdxString(), clientVersion, processName, batchName, throwOnError);
#endif
            Func <AnalyzerStatistics> analyzeProcedure = () =>
            {
                ExecutionProgressControl?.StartMonitor_Batch();
                try
                {
                    var batchID = Guid.NewGuid();

                    var coldCacheExecutionResult = AnalysisServicesHelper.ExecuteForDataSet(_connectionString, commandAnalyze(batchID, clearCacheMode), _cancellationTokenSource.Token).ToAnalyzerExecutionResult(dispose: true);
                    var warmCacheExecutionResult = AnalysisServicesHelper.ExecuteForDataSet(_connectionString, commandAnalyze(batchID, ClearCacheMode.Nothing), _cancellationTokenSource.Token).ToAnalyzerExecutionResult(dispose: true);

                    return(AnalyzerStatistics.CreateFromAnalyzerExecutionResults(coldCacheExecutionResult, warmCacheExecutionResult));
                }
                finally
                {
                    ExecutionProgressControl?.StopMonitor_Batch();
                }
            };

            using (_cancellationTokenSource = new CancellationTokenSource())
            {
                using (var task = Task.Factory.StartNew(analyzeProcedure))
                    return(await task.ConfigureAwait(continueOnCapturedContext : false));
            }
        }
        /// <summary>
        /// Load Xml debug file
        /// </summary>
        public async Task <AnalyzerStatistics> AnalyzeFromDebugAsync(string coldCacheDebugFile, string warmCacheDebugFile)
        {
            #region Argument exception

            if (coldCacheDebugFile == null)
            {
                throw new ArgumentNullException("coldCacheDebugFile");
            }

            if (warmCacheDebugFile == null)
            {
                throw new ArgumentNullException("warmCacheDebugFile");
            }

            #endregion

            Func <AnalyzerStatistics> analyzeProcedure = () =>
            {
                AnalyzerExecutionResult coldCacheExecutionResult;
                AnalyzerExecutionResult warmCacheExecutionResult;

                using (var data = new DataSet())
                {
                    data.ReadXml(coldCacheDebugFile, XmlReadMode.ReadSchema);
                    coldCacheExecutionResult = data.ToAnalyzerExecutionResult(dispose: true);
                }

                using (var data = new DataSet())
                {
                    data.ReadXml(warmCacheDebugFile, XmlReadMode.ReadSchema);
                    warmCacheExecutionResult = data.ToAnalyzerExecutionResult(dispose: true);
                }

                return(AnalyzerStatistics.CreateFromAnalyzerExecutionResults(coldCacheExecutionResult, warmCacheExecutionResult));
            };

            using (var task = Task.Factory.StartNew(analyzeProcedure))
                return(await task.ConfigureAwait(continueOnCapturedContext : false));
        }
        /// <summary>
        /// Execute server-side Analyze procedure
        /// </summary>
        public async Task <AnalyzerStatistics> AnalyzeAsync(string statement, ClearCacheMode clearCacheMode = ClearCacheMode.Default, int queryResultRowLimit = 0)
        {
            #region Argument exception

            if (statement == null)
            {
                throw new ArgumentNullException("statement");
            }

            #endregion

            var currentProcess = Process.GetCurrentProcess();
            var processName    = currentProcess.ProcessName;
            var clientVersion  = "{0} ({1})".FormatWith(currentProcess.MainModule.FileVersionInfo.FileVersion, ClientVersion);

#if DEBUG
            Func <ClearCacheMode, string> commandAnalyze = (cacheMode) => "call {0}.AnalyzeWithDebug(\"{1}\", {2}, {3}, \"{4}\", \"{5}\");".FormatWith(ClrAssemblyID, statement.EscapeMdxString(), (int)cacheMode, queryResultRowLimit, clientVersion, processName);
#else
            Func <ClearCacheMode, string> commandAnalyze = (cacheMode) => "call {0}.Analyze(\"{1}\", {2}, {3}, \"{4}\", \"{5}\");".FormatWith(ClrAssemblyID, statement.EscapeMdxString(), (int)cacheMode, queryResultRowLimit, clientVersion, processName);
#endif
            Action <DataSet, string> saveDebug = (data, dbgType) =>
            {
                if (!DebugToXml)
                {
                    return;
                }

                var debugPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"SSASQueryAnalyzer\debug");
                Directory.CreateDirectory(debugPath);
                data.WriteXml(Path.Combine(debugPath, "AnalyzerExecutionResult-{0:yyyyMMdd-hhmmss-fff}.{1}").FormatWith(DateTime.Now, dbgType), XmlWriteMode.WriteSchema);
            };

            Func <AnalyzerStatistics> analyzeProcedure = () =>
            {
                ExecutionProgressControl?.StartMonitor();
                try
                {
                    AnalyzerExecutionResult coldCacheExecutionResult;
                    AnalyzerExecutionResult warmCacheExecutionResult;

                    using (var data = AnalysisServicesHelper.ExecuteForDataSet(_connectionString, commandAnalyze(clearCacheMode), _cancellationTokenSource.Token))
                    {
                        saveDebug(data, "xqac");
                        coldCacheExecutionResult = data.ToAnalyzerExecutionResult(dispose: true);
                    }

                    ExecutionProgressControl?.ColdCacheExecutionCompleted();

                    using (var data = AnalysisServicesHelper.ExecuteForDataSet(_connectionString, commandAnalyze(ClearCacheMode.Nothing), _cancellationTokenSource.Token))
                    {
                        saveDebug(data, "xqaw");
                        warmCacheExecutionResult = data.ToAnalyzerExecutionResult(dispose: true);
                    }

                    ExecutionProgressControl?.WarmCacheExecutionCompleted();

                    return(AnalyzerStatistics.CreateFromAnalyzerExecutionResults(coldCacheExecutionResult, warmCacheExecutionResult));
                }
                finally
                {
                    ExecutionProgressControl?.StopMonitor();
                }
            };

            using (_cancellationTokenSource = new CancellationTokenSource())
            {
                using (var task = Task.Factory.StartNew(analyzeProcedure))
                    return(await task.ConfigureAwait(continueOnCapturedContext : false));
            }
        }