diff --git a/src/obidms.c b/src/obidms.c index 1c6d1fe..6304f49 100644 --- a/src/obidms.c +++ b/src/obidms.c @@ -19,12 +19,13 @@ #include #include #include -#include /* : Addted the 28 july 2017 to include basename */ +#include /* : Added July 28th 2017 to include basename */ #include "obidms.h" #include "obierrno.h" #include "obidebug.h" #include "obidmscolumn.h" +#include "obiview.h" #include "obiblob_indexer.h" #include "utils.h" #include "obilittlebigman.h" @@ -770,3 +771,321 @@ DIR* opendir_in_dms(OBIDMS_p dms, const char* path_name) return directory; } + + +// TODO move somewhere else maybe +// TODO discuss arguments +obiversion_t obi_import_column(const char* dms_path_1, const char* dms_path_2, const char* column_name, obiversion_t version_number) +{ + OBIDMS_p dms_1; + OBIDMS_p dms_2; + OBIDMS_column_p column_1; + OBIDMS_column_p column_2; + OBIDMS_column_header_p header_1; + OBIDMS_column_header_p header_2; + int avl_exists; + const char* avl_name; + char* new_avl_name; + obiversion_t new_version; + int i; + int avl_count; + char* avl_name_1; + char* avl_name_2; + char* avl_file_path_1; + char* avl_file_path_2; + char* avl_data_file_path_1; + char* avl_data_file_path_2; + char* complete_avl_name; + Obi_indexer_p avl_group; + + dms_1 = obi_open_dms(dms_path_1); + if (dms_1 == NULL) + { + obidebug(1, "\nError opening a DMS to import a column from it"); + return -1; + } + + dms_2 = obi_dms(dms_path_2); + if (dms_2 == NULL) + { + obidebug(1, "\nError opening or creating a DMS to import a column into it"); + return -1; + } + + column_1 = obi_open_column(dms_1, column_name, version_number); + if (column_1 == NULL) + { + obidebug(1, "\nError opening a column to import in another DMS"); + return -1; + } + + header_1 = column_1->header; + + // Check if associated indexer exists BEFORE creating the new column as that will automatically create it if it doesn't already exist + avl_name = header_1->indexer_name; + avl_exists = obi_indexer_exists(dms_2, avl_name); + if (avl_exists == -1) + { + obidebug(1, "\nError checking if an indexer exists while importing a column"); + return -1; + } + if (avl_exists) + // Use automatic name + new_avl_name = NULL; + else + // Name can stay the same + new_avl_name = header_1->indexer_name; + + // Create new column + column_2 = obi_create_column(dms_2, column_name, header_1->returned_data_type, header_1->line_count, + header_1->nb_elements_per_line, header_1->elements_names, true, + new_avl_name, (header_1->associated_column).column_name, (header_1->associated_column).version, + header_1->comments); + + if (column_2 == NULL) + { + obidebug(1, "\nError creating the new column while importing a column"); + return -1; + } + + header_2 = column_2->header; + + // Get the new version to return + new_version = header_2->version; + + // Copy lines_used informations + header_2->lines_used = header_1->lines_used; + + // Copy data TODO check how much time and memory that costs, eventually use write() instead + memcpy(column_2->data, column_1->data, header_1->data_size); + + // Copy the AVL files if there are some (overwriting the automatically created files) + if ((header_1->returned_data_type == OBI_STR) || (header_1->returned_data_type == OBI_SEQ) || (header_1->returned_data_type == OBI_QUAL)) + { + avl_name_1 = (char*) malloc((strlen(header_1->indexer_name) + 1) * sizeof(char)); + if (avl_name_1 == NULL) + { + obi_set_errno(OBI_MALLOC_ERROR); + obidebug(1, "\nError allocating memory for an AVL name when importing a column"); + return -1; + } + strcpy(avl_name_1, header_1->indexer_name); + + avl_name_2 = (char*) malloc((strlen(header_2->indexer_name) + 1) * sizeof(char)); + if (avl_name_2 == NULL) + { + obi_set_errno(OBI_MALLOC_ERROR); + obidebug(1, "\nError allocating memory for an AVL name when importing a column"); + return -1; + } + strcpy(avl_name_2, header_2->indexer_name); + + avl_count = (column_1->indexer->last_avl_idx) + 1; + + // Close column to manipulate AVL files safely (but not multithreading safe) (TODO not sure how important this is, can't find informations about conflicts when using write() on mmapped files) + if (obi_close_column(column_1) < 0) + { + obidebug(1, "\nError closing an imported column"); + return -1; + } + if (obi_close_column(column_2) < 0) + { + obidebug(1, "\nError closing an imported column"); + return -1; + } + + for (i=0; i < avl_count; i++) + { + avl_file_path_1 = obi_get_full_path_of_avl_file_name(dms_1, avl_name_1, i); + if (avl_file_path_1 == NULL) + { + obidebug(1, "\nError getting an AVL file path while importing a column"); + return -1; + } + + avl_data_file_path_1 = obi_get_full_path_of_avl_data_file_name(dms_1, avl_name_1, i); + if (avl_data_file_path_1 == NULL) + { + obidebug(1, "\nError getting an AVL file path while importing a column"); + return -1; + } + avl_file_path_2 = obi_get_full_path_of_avl_file_name(dms_2, avl_name_2, i); + if (avl_file_path_2 == NULL) + { + obidebug(1, "\nError getting an AVL file path while importing a column"); + return -1; + } + avl_data_file_path_2 = obi_get_full_path_of_avl_data_file_name(dms_2, avl_name_2, i); + if (avl_data_file_path_2 == NULL) + { + obidebug(1, "\nError getting an AVL file path while importing a column"); + return -1; + } + + // Copy AVL file + if (copy_file(avl_file_path_1, avl_file_path_2) < 0) + { + obidebug(1, "\nError copying an AVL file while importing a column"); + return -1; + } + + // Copy AVL data file + if (copy_file(avl_data_file_path_1, avl_data_file_path_2) < 0) + { + obidebug(1, "\nError copying a data AVL file while importing a column"); + return -1; + } + + free(avl_file_path_1); + free(avl_file_path_2); + free(avl_data_file_path_1); + free(avl_data_file_path_2); + } + + // Update AVL names in headers + avl_group = obi_open_indexer(dms_2, avl_name_2); + for (i=0; i < avl_count; i++) + { + complete_avl_name = obi_build_avl_name_with_idx(avl_name_2, i); + strcpy((((avl_group->sub_avls)[i])->header)->avl_name, complete_avl_name); + strcpy(((((avl_group->sub_avls)[i])->data)->header)->avl_name, complete_avl_name); + free(complete_avl_name); + } + + free(avl_name_1); + free(avl_name_2); + } + else + { + if (obi_close_column(column_1) < 0) + { + obidebug(1, "\nError closing an imported column"); + return -1; + } + if (obi_close_column(column_2) < 0) + { + obidebug(1, "\nError closing an imported column"); + return -1; + } + } + + // Copy associated column (update version) + //new_associated_col_version = import_column(dms_path_1, dms_path_2, header_1->associated_column_name, header_1->associated_column_version); + // TODO no? because if iterating over all columns in a view etc.... iterate and change associated columns version refs afterwards? + + // Close the DMS + obi_close_dms(dms_1); + obi_close_dms(dms_2); + + return new_version; +} + + +// TODO move somewhere else maybe +// TODO discuss arguments +int obi_import_view(const char* dms_path_1, const char* dms_path_2, const char* view_name_1, const char* view_name_2) +{ + OBIDMS_p dms_1; + OBIDMS_p dms_2; + Obiview_p view_1; + Obiview_p view_2; + obiversion_t new_version; + int i; + + dms_1 = obi_open_dms(dms_path_1); + if (dms_1 == NULL) + { + obidebug(1, "\nError opening a DMS to import a view from it"); + return -1; + } + + dms_2 = obi_dms(dms_path_2); + if (dms_2 == NULL) + { + obidebug(1, "\nError opening or creating a DMS to import a view into it"); + return -1; + } + + // Open view to import + view_1 = obi_open_view(dms_1, view_name_1); + + // Create new view + if (strcmp((view_1->infos)->view_type, VIEW_TYPE_NUC_SEQS) == 0) + view_2 = obi_new_view_nuc_seqs(dms_2, view_name_2, NULL, NULL, (view_1->infos)->comments, false); + else // Non-typed view + view_2 = obi_new_view(dms_2, view_name_2, NULL, NULL, (view_1->infos)->comments); + + // Import line count + view_2->infos->line_count = view_1->infos->line_count; + + // Import the line selection column if there is one + if (! view_1->infos->all_lines) + { + view_2->infos->all_lines = false; + new_version = obi_import_column(dms_path_1, dms_path_2, ((view_1->infos)->line_selection).column_name, ((view_1->infos)->line_selection).version); + if (new_version == -1) + { + obidebug(1, "\nError importing a line selection column while importing a view"); + return -1; + } + strcpy(((view_2->infos)->line_selection).column_name, ((view_1->infos)->line_selection).column_name); + ((view_2->infos)->line_selection).version = new_version; + view_2->line_selection = obi_open_column(dms_2, ((view_2->infos)->line_selection).column_name, ((view_2->infos)->line_selection).version); + if (view_2->line_selection == NULL) + { + obidebug(1, "\nError opening a line selection column while importing a view"); + return -1; + } + } + + // Import each column and update with the new version number + for (i=0; i < (view_1->infos->column_count); i++) + { + new_version = obi_import_column(dms_path_1, dms_path_2, ((((view_1->infos)->column_references)[i]).column_refs).column_name, ((((view_1->infos)->column_references)[i]).column_refs).version); + if (new_version == -1) + { + obidebug(1, "\nError importing a column while importing a view"); + return -1; + } + + if (obi_view_add_column(view_2, + ((((view_1->infos)->column_references)[i]).column_refs).column_name, + new_version, + (((view_1->infos)->column_references)[i]).alias, + 0, + 0, + 0, + NULL, + NULL, + NULL, + -1, + NULL, + false) < 0) + { + obidebug(1, "\nError adding a column to a view while importing it"); + return -1; + } + } + + // Close the views + if (obi_save_and_close_view(view_1) < 0) + { + obidebug(1, "\nError closing a view after importing from it"); + return -1; + } + if (obi_save_and_close_view(view_2) < 0) + { + obidebug(1, "\nError closing a view after importing it"); + return -1; + } + + // Close the DMS + obi_close_dms(dms_1); + obi_close_dms(dms_2); + + return 0; +} + + + + diff --git a/src/obidms.h b/src/obidms.h index a7db2f5..9055c07 100644 --- a/src/obidms.h +++ b/src/obidms.h @@ -361,4 +361,46 @@ char* obi_dms_get_full_path(OBIDMS_p dms, const char* path_name); DIR* opendir_in_dms(OBIDMS_p dms, const char* path_name); +/** + * @brief Imports a column, copying it from a DMS to another DMS, and returns the version of the column in the destination DMS. + * + * The eventual associated indexers are imported too. If an indexer with the same name already exists in the destination DMS, + * they are not merged, the imported indexer is renamed. + * + * @warning The eventual associated column is not imported and needs to be imported separately. + * + * @param dms_path_1 The path to the source DMS (without the '.obidms' extension). + * @param dms_path_2 The path to the destination DMS (without the '.obidms' extension). It is created if it doesn't already exist. + * @param column_name The name of the column to import. + * @param version_number The version of the column to import. + * + * @returns The new version of the column in the destination DMS. + * @retval -1 if an error occurred. + * + * @since August 2017 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +obiversion_t obi_import_column(const char* dms_path_1, const char* dms_path_2, const char* column_name, obiversion_t version_number); + + +/** + * @brief Imports a view, copying it and all its associated columns from a DMS to another DMS. + * + * All the columns and the eventual associated indexers are imported. If an indexer with the same name already exists in the destination DMS, + * they are not merged, the imported indexer is renamed. + * + * @param dms_path_1 The path to the source DMS (without the '.obidms' extension). + * @param dms_path_2 The path to the destination DMS (without the '.obidms' extension). It is created if it doesn't already exist. + * @param view_name_1 The name of the view to import. + * @param view_name_2 The name of the imported view in the destination DMS. + * + * @retval 0 on success. + * @retval -1 if an error occurred. + * + * @since August 2017 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +int obi_import_view(const char* dms_path_1, const char* dms_path_2, const char* view_name_1, const char* view_name_2); + + #endif /* OBIDMS_H_ */