/// <summary> /// Ejecuta una sentencia SQL /// </summary> public async Task <(bool executed, List <string> errors)> ExecuteAsync(string sql, Dictionary <string, object> parameters, CancellationToken cancellationToken) { // Ejecuta la sentencia using (BlockLogModel block = Manager.Logger.Default.CreateBlock(LogModel.LogType.Info, "Execute script")) { if (string.IsNullOrWhiteSpace(sql)) { Errors.Add("The query is empty"); } else { ArgumentListModel arguments = GetArguments(parameters); List <SqlSectionModel> scripts = new SqlParser().Tokenize(sql, arguments.Constants.ToDictionary(), out string error); if (!string.IsNullOrWhiteSpace(error)) { Errors.Add(error); } else { int scriptsExecuted = 0; // Ejecuta los scripts if (scripts.Count > 0) { scriptsExecuted = await ExecuteCommandsAsync(block, _dbProvider, scripts, ConvertParameters(_dbProvider, arguments.Parameters), _timeout, cancellationToken); } // Log if (scriptsExecuted == 0) { Errors.Add("The query is empty"); } else { block.Info($"{scriptsExecuted} command/s executed"); } } } } // Indica que se ha ejecutado return(Errors.Count == 0, Errors); }
/// <summary> /// Exporta una tabla particionando la consulta en varios <see cref="IDataReader"/> (porque por ejemplo spark carga todo el dataReader en memoria /// y da un error de OutOfMemory) /// </summary> private void ExportTable(BlockLogModel block, ConnectionModel connection, ConnectionTableModel table, string path, SolutionManager.FormatType formatType, long blockSize) { IDbProvider provider = Manager.DbScriptsManager.GetDbProvider(connection); long records = 0; int totalPages = 1; // Si es una conexión a Spark, se va a paginar si se supera el número de registros por blogue if (connection.Type == ConnectionModel.ConnectionType.Spark) { records = provider.GetRecordsCount($"SELECT * FROM {provider.SqlHelper.FormatName(table.Schema, table.Name)}", null, connection.TimeoutExecuteScript) ?? 0; totalPages = (int)Math.Ceiling((double)(records / blockSize)) + 1; } // Obtiene los datos for (int actualPage = 0; actualPage < totalPages; actualPage++) { string fileName; string sql; // Obtiene el nombre de archivo if (totalPages == 1) { fileName = GetFileName(path, table.Name, formatType); } else { fileName = GetFileName(path, table.Name, formatType, actualPage + 1); } // Graba el archivo de la página adecuada if (totalPages == 1) { sql = $"SELECT * FROM {provider.SqlHelper.FormatName(table.Schema, table.Name)}"; } else { sql = GetSparkPaginatedSql(provider, table, actualPage, blockSize); } //Log block.Info($"Reading page {actualPage + 1} / {records / blockSize + 1:#,##0} ({records:#,##0}) from table {table.Name}"); // Exporta la tabla ExportTable(block, provider, sql, fileName, formatType, connection.TimeoutExecuteScript); } }
/// <summary> /// Obtiene los comandos para exportación de los archivos asociados a las tablas /// </summary> private List <SentenceExportCsv> GetExportFileSentences(BlockLogModel block, ProviderModel provider, SentenceExportCsvSchema sentence) { List <SentenceExportCsv> sentences = new List <SentenceExportCsv>(); // Obtiene las sentencias foreach (TableDbModel table in provider.LoadSchema().Tables) { if (sentence.ExcludeRules.CheckMustExclude(table.Name)) { block.Info($"Skip table {table.Name} because is excluded"); } else { sentences.Add(CreateSentence(sentence, table)); } } // Devuelve la colección de instrucciones return(sentences); }
/// <summary> /// Ejecuta los comandos de una cadena SQL /// </summary> internal async Task ExecuteAsync(IDbProvider provider, string sql, Models.ArgumentListModel arguments, TimeSpan timeout, CancellationToken cancellationToken) { using (BlockLogModel block = Manager.Logger.Default.CreateBlock(LogModel.LogType.Info, "Execute script")) { if (string.IsNullOrWhiteSpace(sql)) { block.Error("The query is empty"); } else { List <SqlSectionModel> scripts = new SqlParser().Tokenize(sql, arguments.Constants.ToDictionary(), out string error); if (!string.IsNullOrWhiteSpace(error)) { block.Error(error); } else { int scriptsExecuted = 0; // Ejecuta los scripts if (scripts.Count > 0) { scriptsExecuted = await ExecuteCommandsAsync(block, provider, scripts, ConvertParameters(provider, arguments.Parameters), timeout, cancellationToken); } // Log if (scriptsExecuted == 0) { block.Error("The query is empty"); } else { block.Info($"{scriptsExecuted} command/s executed"); } } } } }
/// <summary> /// Procesa un borrado de archivos /// </summary> private async Task ProcessDeleteAsync(BlockLogModel parent, DeleteSentence sentence) { // Evita el warning await Task.Delay(1); // Borra los archivos / directorios using (BlockLogModel block = parent.CreateBlock(LogModel.LogType.Info, $"Start delete '{sentence.Path}'")) { string path = Step.Project.GetFullFileName(sentence.Path); try { if (Directory.Exists(path)) { if (!string.IsNullOrWhiteSpace(sentence.Mask)) { LibHelper.Files.HelperFiles.KillFiles(path, sentence.Mask); } else { LibHelper.Files.HelperFiles.KillPath(path); } } else if (File.Exists(path)) { LibHelper.Files.HelperFiles.KillFile(path); } else { block.Info($"Cant find file or path '{path}' for delete"); } } catch (Exception exception) { AddError(block, $"Error when delete '{path}'. {exception.Message}"); } } }
/// <summary> /// Sube un archivo al blob /// </summary> private async Task ProcessUploadAsync(BlockLogModel parent, UploadBlobSentence sentence) { using (BlockLogModel block = parent.CreateBlock(LogModel.LogType.Info, $"Start uploading to '{sentence.Target.ToString()}'")) { CloudConnection connection = GetConnection(sentence.StorageKey); if (connection == null) { AddError(block, $"Can't find the connection for '{sentence.StorageKey}'"); } else { string fileName = Step.Project.GetFullFileName(sentence.FileName); if (!System.IO.File.Exists(fileName)) { AddError(block, $"Can't find the file '{fileName}'"); } else { try { // Sube el archivo using (ICloudStorageManager manager = new StorageManager().OpenAzureStorageBlob(connection.StorageConnectionString)) { await manager.UploadAsync(GetContainerName(sentence.Target.Container), sentence.Target.Blob, fileName); } // Log block.Info($"Uploaded file '{sentence.FileName}' to '{sentence.Target.ToString()}'"); } catch (Exception exception) { AddError(block, $"Error when upload '{sentence.FileName}' to '{sentence.Target.ToString()}'", exception); } } } } }
/// <summary> /// Abre la ventana de creación de archivos de pruebas /// </summary> private async Task CreateTestXmlAsync() { Details.EtlProjects.CreateTestXmlViewModel viewModel = new Details.EtlProjects.CreateTestXmlViewModel(this); if (MainController.OpenDialog(viewModel) == BauMvvm.ViewModels.Controllers.SystemControllerEnums.ResultType.Yes) { using (BlockLogModel block = MainController.Logger.Default.CreateBlock(LogModel.LogType.Info, "Comienzo de la creación de proyectos de pruebas")) { XmlTestProjectGenerator generator = new XmlTestProjectGenerator(Manager, viewModel.ComboConnections.GetSelectedConnection(), viewModel.DataBase, viewModel.OutputPath); // Genera los archivos try { if (!await generator.GenerateAsync(block, viewModel.Provider, viewModel.PathVariable, viewModel.DataBaseVariable, viewModel.SufixTestTables, viewModel.FileNameTest, viewModel.FileNameAssert, System.Threading.CancellationToken.None)) { block.Error($"Error en la generación de los archivos de pruebas. {generator.Errors.Concatenate()}"); } else { block.Info("Fin de la creación de proyectos de pruebas"); MainController.MainWindowController .ShowNotification(BauMvvm.ViewModels.Controllers.SystemControllerEnums.NotificationType.Information, "Generación de proyectos XML", "Ha terminado correctamente la generación del archivo de pruebas"); } } catch (Exception exception) { block.Error($"Error en la generación de los archivos de pruebas {exception.Message}"); } // Log MainController.Logger.Flush(); } } }
/// <summary> /// Ejecuta una sentencia de proceso /// </summary> private async Task ProcessExecuteAsync(BlockLogModel parent, ExecuteSentence sentence) { // Evita el warning await Task.Delay(1); // Ejecuta la sentencia using (BlockLogModel block = parent.CreateBlock(LogModel.LogType.Info, $"Start execution '{sentence.Process}'")) { try { LibHelper.Processes.SystemProcessHelper processor = new LibHelper.Processes.SystemProcessHelper(); // Ejecuta el proceso processor.ExecuteApplication(sentence.Process, ConvertArguments(sentence.Arguments), true, sentence.Timeout); // Log block.Info($"End execution '{sentence.Process}'"); } catch (Exception exception) { AddError(block, $"Error when execute '{sentence.Process}'. {exception.Message}"); } } }
/// <summary> /// Exporta una tabla de datos a un archivo /// </summary> internal async Task <(bool exported, string error)> ExportAsync(LibLogger.Core.LogManager logManager, string fileName, DbDataReader reader, CancellationToken cancellationToken) { string error = string.Empty; // Exporta el archivo using (BlockLogModel block = logManager.Default.CreateBlock(LogModel.LogType.Info, $"Comienzo de grabación del archivo {fileName}")) { // Exporta el archivo try { if (fileName.EndsWith(".csv", StringComparison.CurrentCultureIgnoreCase)) { await ExportToCsvAsync(block, fileName, reader, cancellationToken); } else if (fileName.EndsWith(".parquet", StringComparison.CurrentCultureIgnoreCase)) { await ExportToParquetAsync(block, fileName, reader, cancellationToken); } else { error = "No se reconoce la extensión del archivo"; } } catch (Exception exception) { error = $"Error al grabar el archivo {fileName}. {exception.Message}"; block.Error(error, exception); } // Log block.Info($"Fin de grabación del archivo {fileName}"); logManager.Flush(); } // Devuelve el valor que indica si se ha exportado el archivo return(string.IsNullOrEmpty(error), error); }
/// <summary> /// Obtiene el datatable de una consulta /// </summary> internal async Task <DataTable> GetDataTableAsync(IDbProvider provider, string query, Models.ArgumentListModel arguments, int actualPage, int pageSize, TimeSpan timeout, CancellationToken cancellationToken) { DataTable result = null; // Normaliza los argumentos if (arguments == null) { arguments = new Models.ArgumentListModel(); } // Obtiene la tabla using (BlockLogModel block = Manager.Logger.Default.CreateBlock(LogModel.LogType.Info, "Execute query")) { if (string.IsNullOrWhiteSpace(query)) { block.Error("The query is empty"); } else { List <SqlSectionModel> scripts = new SqlParser().Tokenize(query, arguments.Constants.ToDictionary(), out string error); if (!string.IsNullOrWhiteSpace(error)) { block.Error(error); } else { ParametersDbCollection parametersDb = ConvertParameters(provider, arguments.Parameters); // Obtiene el datatable foreach (SqlSectionModel script in scripts) { if (script.Type == SqlSectionModel.SectionType.Sql) { string sql = provider.SqlHelper.ConvertSqlNoParameters(script.Content, parametersDb).TrimIgnoreNull(); if (!string.IsNullOrWhiteSpace(sql)) { // Log block.Info($"Executing: {sql}"); // Obtiene la consulta if (sql.StartsWith("SELECT", StringComparison.CurrentCultureIgnoreCase) || sql.StartsWith("WITH ", StringComparison.CurrentCultureIgnoreCase) || sql.StartsWith("EXECUTE ", StringComparison.CurrentCultureIgnoreCase) || sql.StartsWith("EXEC ", StringComparison.CurrentCultureIgnoreCase)) { if (pageSize == 0) { result = await provider.GetDataTableAsync(sql, null, CommandType.Text, timeout, cancellationToken); } else { result = await provider.GetDataTableAsync(sql, null, CommandType.Text, actualPage, pageSize, timeout, cancellationToken); } } else { result = await ExecuteScalarQueryAsync(provider, sql, timeout, cancellationToken); } } } } // Log block.Info("End query"); } } } // Devuelve la última tabla obtenida return(result); }