/******************************************************************** * Obiview functions * ********************************************************************/ /** * @file obiview.c * @author Celine Mercier (celine.mercier@metabarcoding.org) * @date 16 December 2015 * @brief Obiview functions. */ #include #include #include #include #include #include "obiview.h" #include "obidms.h" #include "obidmscolumn.h" #include "obidmscolumn_idx.h" #include "obidmscolumn_bool.h" #include "obidmscolumn_char.h" #include "obidmscolumn_float.h" #include "obidmscolumn_int.h" #include "obidmscolumn_qual.h" #include "obidmscolumn_seq.h" #include "obidmscolumn_str.h" #include "obierrno.h" #include "obidebug.h" #include "obilittlebigman.h" #include "utils.h" #define DEBUG_LEVEL 0 // TODO has to be defined somewhere else (cython compil flag?) /************************************************************************** * * D E C L A R A T I O N O F T H E P R I V A T E F U N C T I O N S * **************************************************************************/ /** * Internal function building the file name where the informations about an obiview are stored. * * @warning The returned pointer has to be freed by the caller. * * @returns A pointer to the file name. * @retval NULL if an error occurred. * * @param view_name The name of the view. * * @since June 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ static char* build_obiview_file_name(const char* view_name); // TODO delete after discussion /** * @brief Internal function creating a file containing all the informations on a view. * * The file is named with the name of the view. * * @param dms The DMS to which the view belongs. * @param view_name The name of the view. * * @retval 0 if the operation was successfully completed. * @retval -1 if an error occurred. * * @since June 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ int create_obiview_file(OBIDMS_p dms, const char* view_name); /** * @brief Internal function to update the column references of a view. * * The column references stored in the mapped view infos structures are updated * to match the columns opened in the opened view structure. * * @param view A pointer on the view. * * @since June 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ void update_column_refs(Obiview_p view); /** * @brief Internal function to update the line count in the context of a view. * * All columns of the view are enlarged to contain at least the new line count. * * @warning The view must be writable. * * @param view A pointer on the view. * @param line_count The new line count. * * @returns A value indicating the success of the operation. * @retval 0 if the operation was successfully completed. * @retval -1 if an error occurred. * * @since February 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ int update_lines(Obiview_p view, index_t line_count); /** * @brief Internal function to clone a column in the context of a view. * * Clones with the right line selection and replaces the cloned columns with the new ones in the view. * If there is a line selection, all columns have to be cloned, otherwise only the column of interest is cloned. * * @param view A pointer on the view. * @param column_name The name of the column in the view that should be cloned. * * @returns A pointer on the new column. * @retval NULL if an error occurred. * * @since February 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_name); /** * @brief Internal function preparing to set a value in a column, in the context of a view. * * The function checks that the view is not read-only, clones the column or all columns if needed, * and updates the line count if needed. * * @param view The view. * @param column_pp A pointer on the pointer on the column, to allow replacing the column if it is cloned. * @param line_nb_p A pointer on the index of the line that will be modified, to allow replacing it if needed. * * @retval 0 if the operation was successfully completed. * @retval -1 if an error occurred. * * @since April 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ int prepare_to_set_value_in_column(Obiview_p view, OBIDMS_column_p* column_pp, index_t* line_nb_p); /** * @brief Internal function preparing to get a value from a column, in the context of a view. * * The function checks that the line index is not beyond the current line count of the view, * and modifies it if there is a line selection associated with the view. * * @param view The view. * @param line_nb_p A pointer on the index of the line, to allow replacing it if needed. * * @retval 0 if the operation was successfully completed. * @retval -1 if an error occurred. * * @since April 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ int prepare_to_get_value_from_column(Obiview_p view, index_t* line_nb_p); /****** PREDICATE FUNCTIONS *******/ /** * @brief Internal function checking if a view has a NUC_SEQUENCE_COLUMN column. * * The function checks that the view has a column with the name attributed to obligatory * nucleotide sequence columns. * * @param view The view. * * @returns A boolean value indicating whether the view has a NUC_SEQUENCE_COLUMN column. * * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ bool view_has_nuc_sequence_column(Obiview_p view); /** * @brief Internal function checking if a view has a QUALITY_COLUMN column. * * The function checks that the view has a column with the name attributed to obligatory * quality columns. * * @param view The view. * * @returns A boolean value indicating whether the view has a QUALITY_COLUMN column. * * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ bool view_has_quality_column(Obiview_p view); /** * @brief Internal function checking if a view has a ID_COLUMN column. * * The function checks that the view has a column with the name attributed to obligatory * id columns. * * @param view The view. * * @returns A boolean value indicating whether the view has a ID_COLUMN column. * * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ bool view_has_id_column(Obiview_p view); /** * @brief Internal function checking if a view has a DEFINITION_COLUMN column. * * The function checks that the view has a column with the name attributed to obligatory * definition columns. * * @param view The view. * * @returns A boolean value indicating whether the view has a DEFINITION_COLUMN column. * * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ bool view_has_definition_column(Obiview_p view); /** * @brief Internal function checking that the quality column of a view and the sequence column associated to it * correspond properly: * - when a line is defined for either column, it must also be defined for the other column * - when a line is defined, the lengths of the sequence and of the quality must be equal * * @param view The view. * * @returns A boolean value indicating whether the sequence and quality columns correspond properly. * * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ bool view_check_quality_matches_seq_column(Obiview_p view); /** * @brief Internal function checking one predicate function on a view. * * @param view The view. * @param predicate_function The predicate function to use. * * @returns The boolean value returned by the predicate function. * * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ bool view_check_one_predicate(Obiview_p view, bool (*predicate_function)(Obiview_p view)); /** * @brief Internal function checking all the predicates associated with a view. * * @param view The view. * * @retval 0 if all the predicates are OK. * @retval -1 if at least one predicate was found to be false. * * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ int view_check_all_predicates(Obiview_p view); /************************************************************************ * * D E F I N I T I O N O F T H E P R I V A T E F U N C T I O N S * ************************************************************************/ // TODO //static char* build_obiview_file_name(const char* view_name) //{ // char* file_name; // // // Build file name // file_name = (char*) malloc((strlen(view_name) + 1)*sizeof(char)); // if (file_name == NULL) // { // obi_set_errno(OBI_MALLOC_ERROR); // obidebug(1, "\nError allocating memory for a view file name"); // return NULL; // } // if (sprintf(file_name, view_name) < 0) // { // obi_set_errno(OBIVIEW_ERROR); // obidebug(1, "\nProblem building an obiview file name"); // return NULL; // } // // return file_name; //} size_t get_platform_view_file_size() { size_t obiview_size; size_t rounded_obiview_size; double multiple; obiview_size = sizeof(Obiview_infos_t); multiple = ceil((double) (obiview_size) / (double) getpagesize()); rounded_obiview_size = multiple * getpagesize(); return rounded_obiview_size; } int create_obiview_file(OBIDMS_p dms, const char* view_name) { // char* file_name; int obiview_file_descriptor; size_t file_size; // TODO // // Create file name // file_name = build_obiview_file_name(view_name); // if (file_name == NULL) // return -1; // Create file obiview_file_descriptor = openat(dms->view_dir_fd, view_name, O_RDWR | O_CREAT | O_EXCL, 0777); if (obiview_file_descriptor < 0) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError creating an obiview file"); // free(file_name); return -1; } //free(file_name); // Truncate file to the right size file_size = get_platform_view_file_size(); if (ftruncate(obiview_file_descriptor, file_size) < 0) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError truncating an obiview file to the right size"); close(obiview_file_descriptor); return -1; } close(obiview_file_descriptor); return 0; } void update_column_refs(Obiview_p view) { int i; for (i=0; i < (view->infos)->column_count; i++) { strcpy((((view->infos)->column_references)+i)->column_name, (((view->columns)[i])->header)->name); (((view->infos)->column_references)+i)->version = (((view->columns)[i])->header)->version; } } int update_lines(Obiview_p view, index_t line_count) { int i; for (i=0; i<((view->infos)->column_count); i++) { while (line_count > (((view->columns)[i])->header)->line_count) { // Enlarge the column if (obi_enlarge_column((view->columns)[i]) < 0) return -1; (((view->columns)[i])->header)->lines_used = line_count; } } (view->infos)->line_count = line_count; return 0; } OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_name) { int i; OBIDMS_column_p current_line_selection = NULL; OBIDMS_column_p column = NULL; OBIDMS_column_p column_buffer; // Check that the view is not read-only if (view->read_only) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError trying to delete a column in a read-only view"); return NULL; } if (view->new_line_selection != NULL) // TODO Probably shouldn't happen, trigger error? current_line_selection = view->new_line_selection; else current_line_selection = view->line_selection; for (i=0; i<((view->infos)->column_count); i++) { if ((current_line_selection != NULL) || (!(strcmp((((view->columns)[i])->header)->name, column_name)))) { // Clone with the right line selection and replace (for all columns if there is a line selection) // Save pointer to close column after cloning column_buffer = (view->columns)[i]; // Clone and replace the column in the view (view->columns)[i] = obi_clone_column(view->dms, current_line_selection, (((view->columns)[i])->header)->name, (((view->columns)[i])->header)->version, 1); if ((view->columns)[i] == NULL) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError cloning a column to replace in a view"); return NULL; } // Close old cloned column obi_close_column(column_buffer); if (!(strcmp((((view->columns)[i])->header)->name, column_name))) { // Found the column to return column = (view->columns)[i]; } } } // Close old line selections if (view->line_selection != NULL) { obi_close_column(view->line_selection); view->line_selection = NULL; // Update line selection reference (((view->infos)->line_selection).column_name)[0] = '\0'; ((view->infos)->line_selection).version = -1; } if (view->new_line_selection != NULL) { obi_close_column(view->new_line_selection); view->new_line_selection = NULL; } // Update column references in view infos update_column_refs(view); return column; } int prepare_to_set_value_in_column(Obiview_p view, OBIDMS_column_p* column_pp, index_t* line_nb_p) { char* column_name; // Check that the view is not read-only if (view->read_only) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError trying to set a value in a column in a read-only view"); return -1; } // If there is a line selection associated with the view or if the column // is read-only, all columns or this column respectively must be cloned if ((view->line_selection != NULL) || (!((*column_pp)->writable))) { // Get the right line number if (view->line_selection != NULL) (*line_nb_p) = *(((index_t*) ((view->line_selection)->data)) + (*line_nb_p)); column_name = (char*) malloc(strlen(((*column_pp)->header)->name) * sizeof(char)); if (column_name == NULL) { obi_set_errno(OBI_MALLOC_ERROR); obidebug(1, "\nError trying to allocate memory for a column name"); return -1; } strcpy(column_name, ((*column_pp)->header)->name); (*column_pp) = clone_column_in_view(view, column_name); if ((*column_pp) == NULL) { obidebug(1, "\nError trying to clone a column to modify it"); return -1; } free(column_name); } if (((*line_nb_p)+1) > (view->infos)->line_count) { if (update_lines(view, ((*line_nb_p)+1)) < 0) return -1; } return 0; } int prepare_to_get_value_from_column(Obiview_p view, index_t* line_nb_p) { if (((*line_nb_p)+1) > ((view->infos)->line_count)) { obi_set_errno(OBICOL_UNKNOWN_ERROR); obidebug(1, "\nError trying to get a value that is beyond the current line count of the view"); return -1; } if (view->line_selection) (*line_nb_p) = *(((index_t*) ((view->line_selection)->data)) + (*line_nb_p)); return 0; } /****** PREDICATE FUNCTIONS *******/ bool view_has_nuc_sequence_column(Obiview_p view) { if (obi_view_get_column(view, NUC_SEQUENCE_COLUMN) != NULL) return true; else return false; } bool view_has_quality_column(Obiview_p view) { if (obi_view_get_column(view, QUALITY_COLUMN) != NULL) return true; else return false; } bool view_has_id_column(Obiview_p view) { if (obi_view_get_column(view, ID_COLUMN) != NULL) return true; else return false; } bool view_has_definition_column(Obiview_p view) { if (obi_view_get_column(view, DEFINITION_COLUMN) != NULL) return true; else return false; } bool view_check_quality_matches_seq_column(Obiview_p view) // TODO Print error if there is one? { index_t i, j; index_t nb_elements_per_line; int qual_len; const uint8_t* qual; char* seq; OBIDMS_column_p qual_column; OBIDMS_column_p seq_column; qual_column = obi_view_get_column(view, QUALITY_COLUMN); if (qual_column == NULL) return false; seq_column = obi_view_get_column(view, NUC_SEQUENCE_COLUMN); // TODO Get associated nuc column if (seq_column == NULL) return false; nb_elements_per_line = (qual_column->header)->nb_elements_per_line; // Check that the quality and the sequence columns have the same number of elements per line if (nb_elements_per_line != (seq_column->header)->nb_elements_per_line) return false; for (i=0; i < (view->infos)->line_count; i++) { for (j=0; j < nb_elements_per_line; j++) { qual = obi_column_get_obiqual_int_with_elt_idx(qual_column, i, j, &qual_len); seq = obi_column_get_obiseq_with_elt_idx(seq_column, i, j); if ((qual != OBIQual_int_NA) && (seq != OBISeq_NA)) { // Test that the lengths of the quality and the sequence are equal if (qual_len != (int)strlen(seq)) return false; } // Test if one value is NA and not the other else if (((qual == OBIQual_int_NA) && (seq != OBISeq_NA)) || ((qual != OBIQual_int_NA) && (seq == OBISeq_NA))) return false; } } return true; } bool view_check_one_predicate(Obiview_p view, bool (*predicate_function)(Obiview_p view)) { return predicate_function(view); } int view_check_all_predicates(Obiview_p view) { int i; for (i=0; i < view->nb_predicates; i++) { if (view_check_one_predicate(view, (view->predicate_functions)[i]) == false) return -1; } return 0; } // TODO predicate function that goes through each line / each elements /********************************************************************** * * D E F I N I T I O N O F T H E P U B L I C F U N C T I O N S * **********************************************************************/ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_clone, index_t* line_selection, const char* comments) { Obiview_p view; int i; index_t line_nb; struct dirent* dp; // Check uniqueness of name while ((dp = readdir(dms->view_directory)) != NULL) { if ((dp->d_name)[0] == '.') continue; if (strcmp(dp->d_name, view_name) == 0) // TODO change if view name building changes { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nName of new view already exists"); return NULL; } } // Allocate memory for view structure view = (Obiview_p) malloc(sizeof(Obiview_t)); if (view == NULL) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError allocating memory for a view"); return NULL; } view->dms = dms; // Create view file if (create_obiview_file(dms, view_name) < 0) { free(view); return NULL; } // Map view file view->infos = obi_view_map_file(dms, view_name); if (view->infos == NULL) { obidebug(1, "\nError mapping the informations of a new view"); free(view); return NULL; } // Clone view to clone if there is one if (view_to_clone != NULL) { if (!(view_to_clone->read_only)) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nA view can not be cloned if it is not read-only"); obi_view_unmap_file(view->dms, view->infos); free(view); return NULL; } // If the view to clone has an associated line selection and there is no new line selection, open the associated line selection if ((view_to_clone->line_selection != NULL) && (line_selection == NULL)) { view->line_selection = obi_open_column(dms, ((view_to_clone->line_selection)->header)->name, ((view_to_clone->line_selection)->header)->version); if (view->line_selection == NULL) { obi_view_unmap_file(view->dms, view->infos); free(view); return NULL; } (view->infos)->line_count = (view_to_clone->infos)->line_count; } // If there is a new line selection, build it by combining it with the one from the view to clone if there is one else if (line_selection != NULL) { view->line_selection = obi_create_column(view->dms, LINES_COLUMN_NAME, OBI_IDX, 0, 1, LINES_COLUMN_NAME, NULL, NULL); if ((view->line_selection) == NULL) { obidebug(1, "\nError creating a column corresponding to a line selection"); obi_view_unmap_file(view->dms, view->infos); free(view); return NULL; } (view->infos)->all_lines = false; (view->infos)->line_count = 0; i = 0; for (i=0; line_selection[i] != -1; i++) { line_nb = line_selection[i]; if (line_nb > (view_to_clone->infos)->line_count) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError trying to select a line for a new view that is beyond the line count of the view to clone"); obi_close_column(view->line_selection); obi_view_unmap_file(view->dms, view->infos); free(view); return NULL; } if (view_to_clone->line_selection != NULL) line_nb = obi_column_get_index(view_to_clone->line_selection, line_nb); if (obi_column_set_index(view->line_selection, ((view->line_selection)->header)->lines_used, line_nb) < 0) { obi_close_column(view->line_selection); obi_view_unmap_file(view->dms, view->infos); free(view); return NULL; } // Update view line count ((view->infos)->line_count)++; } } else // If there is no line selection associated with the view to clone or the new view { view->line_selection = NULL; (view->infos)->all_lines = true; (view->infos)->line_count = (view_to_clone->infos)->line_count; } for (i=0; i<((view_to_clone->infos)->column_count); i++) { (view->columns)[i] = obi_open_column(dms, (((view_to_clone->columns)[i])->header)->name, (((view_to_clone->columns)[i])->header)->version); if ((view->columns)[i] == NULL) { if (view->line_selection != NULL) obi_close_column(view->line_selection); obi_view_unmap_file(view->dms, view->infos); free(view); return NULL; } } (view->infos)->column_count = (view_to_clone->infos)->column_count; strcpy((view->infos)->view_type, (view_to_clone->infos)->view_type); strcpy((view->infos)->created_from, (view_to_clone->infos)->name); view->new_line_selection = NULL; } // Else, fill empty view structure else { (view->infos)->column_count = 0; (view->infos)->line_count = 0; (view->infos)->all_lines = true; view->line_selection = NULL; view->new_line_selection = NULL; ((view->infos)->created_from)[0] = '\0'; ((view->infos)->view_type)[0] = '\0'; //view->columns = NULL; // TODO } strcpy((view->infos)->name, view_name); strcpy((view->infos)->comments, comments); (view->infos)->creation_date = time(NULL); view->read_only = 0; view->nb_predicates = 0; view->predicate_functions = NULL; // Store reference for line selection if (view->line_selection == NULL) { (((view->infos)->line_selection).column_name)[0] = '\0'; ((view->infos)->line_selection).version = -1; } else { strcpy(((view->infos)->line_selection).column_name, ((view->line_selection)->header)->name); ((view->infos)->line_selection).version = ((view->line_selection)->header)->version; } // Store references for columns update_column_refs(view); return view; } Obiview_p obi_new_view_cloned_from_name(OBIDMS_p dms, const char* view_name, const char* view_to_clone_name, index_t* line_selection, const char* comments) { Obiview_p view; Obiview_p view_to_clone; view_to_clone = obi_open_view(dms, view_to_clone_name); if (view_to_clone == NULL) return NULL; view = obi_new_view(dms, view_name, view_to_clone, line_selection, comments); obi_close_view(view_to_clone); return view; } Obiview_p obi_new_view_nuc_seqs(OBIDMS_p dms, const char* view_name, Obiview_p view_to_clone, index_t* line_selection, const char* comments) { Obiview_p view; if (view_to_clone != NULL) { // Check that the view to clone is already a NUC_SEQS view (TODO discuss possibility of transforming type of a view) if (strcmp((view_to_clone->infos)->view_type, VIEW_TYPE_NUC_SEQS)) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "Trying to clone a non-NUC SEQS view to create a NUC SEQS view"); return NULL; } } view = obi_new_view(dms, view_name, view_to_clone, line_selection, comments); if (view == NULL) return NULL; strcpy((view->infos)->view_type, VIEW_TYPE_NUC_SEQS); if (view_to_clone == NULL) { // Adding sequence column if (obi_view_add_column(view, NUC_SEQUENCE_COLUMN, -1, OBI_SEQ, 0, 1, NUC_SEQUENCE_COLUMN, "", "Nucleotide sequences", true) < 0) { obidebug(1, "Error adding an obligatory column in a nucleotide sequences view"); return NULL; } // Adding id column if (obi_view_add_column(view, ID_COLUMN, -1, OBI_STR, 0, 1, ID_COLUMN, "", "Ids", true) < 0) { obidebug(1, "Error adding an obligatory column in a nucleotide sequences view"); return NULL; } // Adding definition column if (obi_view_add_column(view, DEFINITION_COLUMN, -1, OBI_STR, 0, 1, DEFINITION_COLUMN, "", "Definitions", true) < 0) { obidebug(1, "Error adding an obligatory column in a nucleotide sequences view"); return NULL; } // Adding quality column if (obi_view_add_column(view, QUALITY_COLUMN, -1, OBI_QUAL, 0, 1, QUALITY_COLUMN, "", "Sequence qualities", true) < 0) { obidebug(1, "Error adding an obligatory column in a nucleotide sequences view"); return NULL; } } // Add predicate functions of the view type view->nb_predicates = 5; // TODO macro? view->predicate_functions = malloc((view->nb_predicates) * sizeof(bool (*) (bool))); (view->predicate_functions)[0] = view_has_nuc_sequence_column; (view->predicate_functions)[1] = view_has_quality_column; (view->predicate_functions)[2] = view_has_id_column; (view->predicate_functions)[3] = view_has_definition_column; (view->predicate_functions)[4] = view_check_quality_matches_seq_column; return view; } Obiview_p obi_new_view_nuc_seqs_cloned_from_name(OBIDMS_p dms, const char* view_name, const char* view_to_clone_name, index_t* line_selection, const char* comments) { Obiview_p view; Obiview_p view_to_clone; view_to_clone = obi_open_view(dms, view_to_clone_name); if (view_to_clone == NULL) return NULL; view = obi_new_view_nuc_seqs(dms, view_name, view_to_clone, line_selection, comments); obi_close_view(view_to_clone); return view; } Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name) { // char* file_name; Obiview_infos_p view_infos; int obiview_file_descriptor; size_t file_size; // TODO // // Create file name // file_name = build_obiview_file_name(view_name); // if (file_name == NULL) // return -1; // Open view file obiview_file_descriptor = openat(dms->view_dir_fd, view_name, O_RDWR, 0777); if (obiview_file_descriptor < 0) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError opening an obiview file"); // free(file_name); return NULL; } //free(file_name); // Map the view infos structure file_size = get_platform_view_file_size(); view_infos = mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, obiview_file_descriptor, 0 ); if (view_infos == NULL) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError mapping an obiview file"); return NULL; } close(obiview_file_descriptor); return view_infos; } int obi_view_unmap_file(OBIDMS_p dms, Obiview_infos_p view_infos) { // char* file_name; int obiview_file_descriptor; size_t file_size; // TODO // // Get file name // file_name = build_obiview_file_name(view_name); // if (file_name == NULL) // return -1; // Open view file obiview_file_descriptor = openat(dms->view_dir_fd, view_infos->name, O_RDWR, 0777); if (obiview_file_descriptor < 0) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError opening an obiview file"); // free(file_name); return -1; } //free(file_name); // Unmap the view infos structure file_size = get_platform_view_file_size(); if (munmap(view_infos, file_size) < 0) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError unmapping an obiview file"); close(obiview_file_descriptor); return -1; } close(obiview_file_descriptor); return 0; } Obiview_p obi_open_view(OBIDMS_p dms, const char* view_name) { Obiview_p view; int i; // Alllocate the memory for the view structure view = (Obiview_p) malloc(sizeof(Obiview_t)); if (view == NULL) { obi_set_errno(OBI_MALLOC_ERROR); obidebug(1, "\nError allocating memory for a view"); return NULL; } // Map view file view->infos = obi_view_map_file(dms, view_name); // Open the line selection associated with the view if ((view->infos)->all_lines) view->line_selection = NULL; else { view->line_selection = obi_open_column(dms, ((view->infos)->line_selection).column_name, ((view->infos)->line_selection).version); if (view->line_selection == NULL) { obidebug(1, "\nError opening a line selection for a view"); obi_view_unmap_file(view->dms, view->infos); free(view); return NULL; } } // Open the columns to read for (i=0; i < ((view->infos)->column_count); i++) { (view->columns)[i] = obi_open_column(dms, (((view->infos)->column_references)+i)->column_name, (((view->infos)->column_references)+i)->version); if ((view->columns)[i] == NULL) { obidebug(1, "\nError opening a column for a view: column %d: %s, version %d", i, (((view->infos)->column_references)+i)->column_name, (((view->infos)->column_references)+i)->version); obi_close_view(view); return NULL; } } view->dms = dms; view->new_line_selection = NULL; view->read_only = true; view->nb_predicates = 0; view->predicate_functions = NULL; return view; } int obi_view_add_column(Obiview_p view, const char* column_name, obiversion_t version_number, OBIType_t data_type, index_t nb_lines, index_t nb_elements_per_line, const char* elements_names, const char* indexer_name, const char* comments, bool create) // all infos for creation or open { int i; OBIDMS_column_p column; OBIDMS_column_p column_buffer; OBIDMS_column_p current_line_selection; // Check that the view is not read-only if (view->read_only) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError trying to add a column in a read-only view"); return -1; } // If there is a line selection, clone the columns to delete it if (view->new_line_selection != NULL) // TODO Probably shouldn't happen, trigger error? current_line_selection = view->new_line_selection; else current_line_selection = view->line_selection; if (current_line_selection != NULL) { for (i=0; i<((view->infos)->column_count); i++) { { // Clone with the right line selection and replace for all columns // Save pointer to close column after cloning column_buffer = (view->columns)[i]; // Clone and replace the column in the view (view->columns)[i] = obi_clone_column(view->dms, current_line_selection, (((view->columns)[i])->header)->name, (((view->columns)[i])->header)->version, 1); if ((view->columns)[i] == NULL) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError cloning a column to replace in a view"); return -1; } // Close old cloned column obi_close_column(column_buffer); } } } // Close old line selections if (view->line_selection != NULL) { obi_close_column(view->line_selection); view->line_selection = NULL; // Update line selection reference (((view->infos)->line_selection).column_name)[0] = '\0'; ((view->infos)->line_selection).version = -1; } if (view->new_line_selection != NULL) { obi_close_column(view->new_line_selection); view->new_line_selection = NULL; } // Update the line count if ((view->infos)->line_count > nb_lines) nb_lines = (view->infos)->line_count; else if (nb_lines > (view->infos)->line_count) update_lines(view, nb_lines); // Open or create the column if (create) { // Create column column = obi_create_column(view->dms, column_name, data_type, nb_lines, nb_elements_per_line, elements_names, indexer_name, comments); } else { // Open column column = obi_open_column(view->dms, column_name, version_number); } if (column == NULL) { obidebug(1, "\nError creating or opening a column to add to a view"); return -1; } // Store column in the view (view->columns)[(view->infos)->column_count] = column; (view->infos)->column_count++; if ((view->infos)->column_count == 1) // first column in the view (view->infos)->line_count = (column->header)->lines_used; // Update reference in view infos update_column_refs(view); return 0; } int obi_view_delete_column(Obiview_p view, const char* column_name) { int i; bool found; // TODO check that not deleting an obligatory column? // Check that the view is not read-only if (view->read_only) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError trying to delete a column in a read-only view"); return -1; } found = 0; for (i=0; i<((view->infos)->column_count); i++) { if (!strcmp((((view->columns)[i])->header)->name, column_name)) { obi_close_column((view->columns)[i]); found = 1; } if (found) { if (i != (((view->infos)->column_count) - 1)) // not the last one (view->columns)[i] = (view->columns)[i+1]; else // Last column (view->columns)[i] = NULL; } } if (!found) return -1; ((view->infos)->column_count)--; // Update reference in view infos update_column_refs(view); return 0; } OBIDMS_column_p obi_view_get_column(Obiview_p view, const char* column_name) { int i; for (i=0; i<((view->infos)->column_count); i++) { if (!(strcmp((((view->columns)[i])->header)->name, column_name))) return (view->columns)[i]; } return NULL; } OBIDMS_column_p* obi_view_get_pointer_on_column_in_view(Obiview_p view, const char* column_name) // TODO delete? { int i; for (i=0; i<((view->infos)->column_count); i++) { if (!(strcmp((((view->columns)[i])->header)->name, column_name))) return ((view->columns)+i); } return NULL; } int obi_select_line(Obiview_p view, index_t line_nb) { // Check that the view is not read-only if (view->read_only) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError trying to select a line in a read-only view"); return -1; } // If the column for line selection doesn't already exists, create it and store its informations if ((view->new_line_selection) == NULL) { view->new_line_selection = obi_create_column(view->dms, LINES_COLUMN_NAME, OBI_IDX, 0, 1, LINES_COLUMN_NAME, NULL, NULL); if ((view->new_line_selection) == NULL) { obidebug(1, "\nError creating a column corresponding to a line selection"); return -1; } } // If we are already working on a line selection, get the pointed line number if (view->line_selection) line_nb = obi_column_get_index(view->line_selection, line_nb); if (obi_column_set_index(view->new_line_selection, ((view->new_line_selection)->header)->lines_used, line_nb) < 0) return -1; return 0; } int obi_select_lines(Obiview_p view, index_t* line_nbs) { int i; index_t line_nb; // Check that the view is not read-only if (view->read_only) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError trying to select a line in a read-only view"); return -1; } // If column for line selection doesn't already exists, create it and store its informations if ((view->new_line_selection) == NULL) { view->new_line_selection = obi_create_column(view->dms, LINES_COLUMN_NAME, OBI_IDX, 0, 1, LINES_COLUMN_NAME, NULL, NULL); if ((view->new_line_selection) == NULL) { obidebug(1, "\nError creating a column corresponding to a line selection"); return -1; } } for (i=0; line_nbs[i] != -1; i++) { line_nb = line_nbs[i]; // If we are already working on a line selection, get the pointed line number if (view->line_selection) line_nb = obi_column_get_index(view->line_selection, line_nb); if (obi_column_set_index(view->new_line_selection, ((view->new_line_selection)->header)->lines_used, line_nb) < 0) return -1; } return 0; } int obi_save_view(Obiview_p view) { // Check that the view is not read-only if (view->read_only) { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError trying to save a read-only view"); return -1; } // Store reference for the line selection associated with that view if there is one if (view->new_line_selection != NULL) { (view->infos)->line_count = ((view->new_line_selection)->header)->lines_used; strcpy(((view->infos)->line_selection).column_name, ((view->new_line_selection)->header)->name); ((view->infos)->line_selection).version = ((view->new_line_selection)->header)->version; (view->infos)->all_lines = false; } else if (view->line_selection != NULL) // Unnecessary in theory { strcpy(((view->infos)->line_selection).column_name, ((view->line_selection)->header)->name); ((view->infos)->line_selection).version = ((view->line_selection)->header)->version; (view->infos)->all_lines = false; } else // Necessary because line selection could have been deleted if a column was cloned { (((view->infos)->line_selection).column_name)[0] = '\0'; ((view->infos)->line_selection).version = -1; (view->infos)->all_lines = true; } update_column_refs(view); return 0; } int obi_close_view(Obiview_p view) { int i; int ret_value; ret_value = 0; for (i=0; i < ((view->infos)->column_count); i++) { if (obi_close_column((view->columns)[i]) < 0) { obidebug(1, "\nError closing a column while closing a view"); ret_value = -1; } } // Close line selections if they exist if (view->line_selection != NULL) { if (obi_close_column(view->line_selection) < 0) { obidebug(1, "\nError closing a line selection while closing a view"); ret_value = -1; } } if (view->new_line_selection != NULL) { if (obi_close_column(view->new_line_selection) < 0) { obidebug(1, "\nError closing a new line selection while closing a view"); ret_value = -1; } } // Unmap view file if (obi_view_unmap_file(view->dms, view->infos) < 0) { obidebug(1, "\nError unmaping a view file while closing a view"); ret_value = -1; } free(view); return ret_value; } int obi_save_and_close_view(Obiview_p view) { if (!(view->read_only)) { if (view_check_all_predicates(view) < 0) return -1; // TODO reverse view (delete files) if (obi_save_view(view) < 0) return -1; } if (obi_close_view(view) < 0) return -1; return 0; } /*********** FOR BOOL COLUMNS ***********/ int obi_column_set_obibool_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx, obibool_t value) { if (prepare_to_set_value_in_column(view, &column, &line_nb) < 0) return -1; return obi_column_set_obibool_with_elt_idx(column, line_nb, element_idx, value); } obibool_t obi_column_get_obibool_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx) { if (prepare_to_get_value_from_column(view, &line_nb) < 0) return OBIBool_NA; return obi_column_get_obibool_with_elt_idx(column, line_nb, element_idx); } int obi_column_set_obibool_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name, obibool_t value) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return -1; return obi_column_set_obibool_with_elt_idx_in_view(view, column, line_nb, element_idx, value); } obibool_t obi_column_get_obibool_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return OBIBool_NA; return obi_column_get_obibool_with_elt_idx_in_view(view, column, line_nb, element_idx); } /****************************************/ /*********** FOR CHAR COLUMNS ***********/ int obi_column_set_obichar_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx, obichar_t value) { if (prepare_to_set_value_in_column(view, &column, &line_nb) < 0) return -1; return obi_column_set_obichar_with_elt_idx(column, line_nb, element_idx, value); } obichar_t obi_column_get_obichar_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx) { if (prepare_to_get_value_from_column(view, &line_nb) < 0) return OBIChar_NA; return obi_column_get_obichar_with_elt_idx(column, line_nb, element_idx); } int obi_column_set_obichar_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name, obichar_t value) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return -1; return obi_column_set_obichar_with_elt_idx_in_view(view, column, line_nb, element_idx, value); } obichar_t obi_column_get_obichar_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return OBIChar_NA; return obi_column_get_obichar_with_elt_idx_in_view(view, column, line_nb, element_idx); } /****************************************/ /*********** FOR FLOAT COLUMNS ***********/ int obi_column_set_obifloat_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx, obifloat_t value) { if (prepare_to_set_value_in_column(view, &column, &line_nb) < 0) return -1; return obi_column_set_obifloat_with_elt_idx(column, line_nb, element_idx, value); } obifloat_t obi_column_get_obifloat_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx) { if (prepare_to_get_value_from_column(view, &line_nb) < 0) return OBIFloat_NA; return obi_column_get_obifloat_with_elt_idx(column, line_nb, element_idx); } int obi_column_set_obifloat_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name, obifloat_t value) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return -1; return obi_column_set_obifloat_with_elt_idx_in_view(view, column, line_nb, element_idx, value); } obifloat_t obi_column_get_obifloat_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return OBIFloat_NA; return obi_column_get_obifloat_with_elt_idx_in_view(view, column, line_nb, element_idx); } /****************************************/ /*********** FOR INT COLUMNS ***********/ int obi_column_set_obiint_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx, obiint_t value) { if (prepare_to_set_value_in_column(view, &column, &line_nb) < 0) return -1; return obi_column_set_obiint_with_elt_idx(column, line_nb, element_idx, value); } obiint_t obi_column_get_obiint_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx) { if (prepare_to_get_value_from_column(view, &line_nb) < 0) return OBIInt_NA; return obi_column_get_obiint_with_elt_idx(column, line_nb, element_idx); } int obi_column_set_obiint_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name, obiint_t value) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return -1; return obi_column_set_obiint_with_elt_idx_in_view(view, column, line_nb, element_idx, value); } obiint_t obi_column_get_obiint_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return OBIInt_NA; return obi_column_get_obiint_with_elt_idx_in_view(view, column, line_nb, element_idx); } /****************************************/ /*********** FOR QUAL COLUMNS ***********/ int obi_column_set_obiqual_char_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx, const char* value) { if (prepare_to_set_value_in_column(view, &column, &line_nb) < 0) return -1; return obi_column_set_obiqual_char_with_elt_idx(column, line_nb, element_idx, value); } int obi_column_set_obiqual_int_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx, const uint8_t* value, int value_length) { if (prepare_to_set_value_in_column(view, &column, &line_nb) < 0) return -1; return obi_column_set_obiqual_int_with_elt_idx(column, line_nb, element_idx, value, value_length); } char* obi_column_get_obiqual_char_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx) { if (prepare_to_get_value_from_column(view, &line_nb) < 0) return OBIQual_char_NA; return obi_column_get_obiqual_char_with_elt_idx(column, line_nb, element_idx); } const uint8_t* obi_column_get_obiqual_int_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx, int* value_length) { if (prepare_to_get_value_from_column(view, &line_nb) < 0) return OBIQual_int_NA; return obi_column_get_obiqual_int_with_elt_idx(column, line_nb, element_idx, value_length); } int obi_column_set_obiqual_char_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name, const char* value) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return -1; return obi_column_set_obiqual_char_with_elt_idx_in_view(view, column, line_nb, element_idx, value); } int obi_column_set_obiqual_int_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name, const uint8_t* value, int value_length) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return -1; return obi_column_set_obiqual_int_with_elt_idx_in_view(view, column, line_nb, element_idx, value, value_length); } char* obi_column_get_obiqual_char_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return OBIQual_char_NA; return obi_column_get_obiqual_char_with_elt_idx_in_view(view, column, line_nb, element_idx); } const uint8_t* obi_column_get_obiqual_int_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name, int* value_length) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return OBIQual_int_NA; return obi_column_get_obiqual_int_with_elt_idx_in_view(view, column, line_nb, element_idx, value_length); } /****************************************/ /*********** FOR SEQ COLUMNS ***********/ int obi_column_set_obiseq_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx, const char* value) { if (prepare_to_set_value_in_column(view, &column, &line_nb) < 0) return -1; return obi_column_set_obiseq_with_elt_idx(column, line_nb, element_idx, value); } char* obi_column_get_obiseq_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx) { if (prepare_to_get_value_from_column(view, &line_nb) < 0) return OBISeq_NA; return obi_column_get_obiseq_with_elt_idx(column, line_nb, element_idx); } int obi_column_set_obiseq_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name, const char* value) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return -1; return obi_column_set_obiseq_with_elt_idx_in_view(view, column, line_nb, element_idx, value); } char* obi_column_get_obiseq_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return OBISeq_NA; return obi_column_get_obiseq_with_elt_idx_in_view(view, column, line_nb, element_idx); } /****************************************/ /*********** FOR STR COLUMNS ***********/ int obi_column_set_obistr_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx, const char* value) { if (prepare_to_set_value_in_column(view, &column, &line_nb) < 0) return -1; return obi_column_set_obistr_with_elt_idx(column, line_nb, element_idx, value); } const char* obi_column_get_obistr_with_elt_idx_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, index_t element_idx) { if (prepare_to_get_value_from_column(view, &line_nb) < 0) return OBIStr_NA; return obi_column_get_obistr_with_elt_idx(column, line_nb, element_idx); } int obi_column_set_obistr_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name, const char* value) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return -1; return obi_column_set_obistr_with_elt_idx_in_view(view, column, line_nb, element_idx, value); } const char* obi_column_get_obistr_with_elt_name_in_view(Obiview_p view, OBIDMS_column_p column, index_t line_nb, const char* element_name) { index_t element_idx = obi_column_get_element_index_from_name(column, element_name); if (element_idx == OBIIdx_NA) return OBIStr_NA; return obi_column_get_obistr_with_elt_idx_in_view(view, column, line_nb, element_idx); } /****************************************/