/// <summary> /// Exporta las tablas de una conexión a una serie de archivos /// </summary> public async Task <bool> ExportAsync(BlockLogModel block, ConnectionModel connection, string dataBase, string path, SolutionManager.FormatType formatType, long blockSize, CancellationToken cancellationToken) { // Limpia los errores Errors.Clear(); // Carga el esquema await Manager.DbScriptsManager.LoadSchemaAsync(connection, cancellationToken); // Crea el directorio LibHelper.Files.HelperFiles.MakePath(path); // Genera los archivos foreach (ConnectionTableModel table in connection.Tables) { if (!cancellationToken.IsCancellationRequested && (string.IsNullOrWhiteSpace(dataBase) || dataBase.Equals(table.Schema, StringComparison.CurrentCultureIgnoreCase))) { try { // Log block.Info($"Start export table {table.FullName}"); // Exporta la tabla await Task.Run(() => ExportTable(block, connection, table, path, formatType, blockSize)); // Log block.Info($"End export table {table.FullName}"); } catch (Exception exception) { block.Error($"Error when export {table.FullName}", exception); } } } // Devuelve el valor que indica si la exportación ha sido correcta return(Errors.Count == 0); }
/// <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 el nombre de archivo /// </summary> internal string GetFileNameTable(string mountPathVariable, string pathValidate, string table, SolutionManager.FormatType formatType, string tablePrefixes) { string extension = "parquet"; // Quita el prefijo de la tabla si es necesario table = RemovePrefix(table, tablePrefixes); // Cambia la extensión si es necesario if (formatType == SolutionManager.FormatType.Csv) { extension = "csv"; } // Devuelve el nombre de la tabla return($"{extension}.`" + "{{" + mountPathVariable + "}}" + $"/{pathValidate}/{table}.{extension}`"); }