LCOV - code coverage report
Current view: top level - src - db_save_prefixes.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 73.8 % 61 45
Test Date: 2026-01-12 05:34:38 Functions: 100.0 % 1 1

            Line data    Source code
       1              : /**
       2              :  * @file precizer.h
       3              :  * @brief Database operations for directory prefix paths
       4              :  */
       5              : 
       6              : #include "precizer.h"
       7              : 
       8              : /**
       9              :  * @brief Saves directory prefix paths into the database
      10              :  *
      11              :  * @details This function handles the storage of directory prefix paths in the database
      12              :  * according to several operational modes:
      13              :  *
      14              :  * Operational Modes:
      15              :  * - Compare Mode: Function returns immediately with SUCCESS
      16              :  * - Force Mode: Previous records are deleted before insertion
      17              :  * - Dry Run Mode: Data insertion occurs in memory only
      18              :  *
      19              :  * Data Insertion Rules:
      20              :  * - Data is inserted only if:
      21              :  *   - Database file is not physical, OR
      22              :  *   - Dry Run mode is not activated
      23              :  * - In Dry Run mode with physical database:
      24              :  *   - Writing occurs to in-memory database only
      25              :  *
      26              :  * Processing Steps:
      27              :  * 1. Checks operational mode
      28              :  * 2. Handles record deletion if in Force mode
      29              :  * 3. Processes path insertions according to insertion rules
      30              :  * 4. Removes trailing slashes from paths before insertion
      31              :  *
      32              :  * Error Handling:
      33              :  * - SQLite preparation errors
      34              :  * - SQLite binding errors
      35              :  * - SQLite execution errors
      36              :  * All errors are logged using slog() function
      37              :  *
      38              :  * @pre config structure must be properly initialized with:
      39              :  *      - compare flag
      40              :  *      - force flag
      41              :  *      - dry_run flag
      42              :  *      - db connection
      43              :  *      - paths array
      44              :  *
      45              :  * @return Return enum value:
      46              :  *      - SUCCESS (0): Paths saved successfully
      47              :  *      - FAILURE (1): Operation failed due to database errors
      48              :  */
      49          184 : Return db_save_prefixes(void)
      50              : {
      51              :         /// The status that will be passed to return() before exiting.
      52              :         /// By default, the function worked without errors.
      53          184 :         Return status = SUCCESS;
      54              : 
      55              :         /* Interrupt the function smoothly */
      56              :         /* Interrupt when Ctrl+C */
      57          184 :         if(global_interrupt_flag == true)
      58              :         {
      59            0 :                 provide(status);
      60              :         }
      61              : 
      62              :         /* Skip in comparison mode */
      63          184 :         if(config->compare == true)
      64              :         {
      65           32 :                 return(status);
      66              :         }
      67              : 
      68          152 :         if(config->force == true && config->dry_run == false)
      69              :         {
      70              :                 /* Delete previous records in the table  */
      71            2 :                 sqlite3_stmt *delete_stmt = NULL;
      72              : 
      73            2 :                 const char *delete_sql = "DELETE FROM paths WHERE ID IN (SELECT path_id FROM runtime_paths_id.the_path_id_does_not_exists);";
      74              : 
      75            2 :                 int rc = sqlite3_prepare_v2(config->db,delete_sql,-1,&delete_stmt,NULL);
      76              : 
      77            2 :                 if(SQLITE_OK != rc)
      78              :                 {
      79            0 :                         log_sqlite_error(config->db,rc,NULL,"Can't prepare delete statement");
      80            0 :                         status = FAILURE;
      81              :                 }
      82              : 
      83            2 :                 if(SUCCESS == status)
      84              :                 {
      85              :                         /* Execute SQL statement */
      86            2 :                         if(sqlite3_step(delete_stmt) != SQLITE_DONE)
      87              :                         {
      88            0 :                                 log_sqlite_error(config->db,rc,NULL,"Delete statement didn't return DONE");
      89            0 :                                 status = FAILURE;
      90              :                         }
      91              :                 }
      92              : 
      93            2 :                 if(SUCCESS == status)
      94              :                 {
      95              :                         /* Reflect changes in global */
      96            2 :                         config->db_primary_file_modified = true;
      97              :                 }
      98              : 
      99            2 :                 sqlite3_finalize(delete_stmt);
     100              :         }
     101              : 
     102              :         /**
     103              :          * @brief Data insertion handling rules
     104              :          * @details Data insertion occurs only if the database file is not a physical file
     105              :          *          and Dry Run mode is not activated. With Dry Run mode activated,
     106              :          *          if a physical file is not opened, writing occurs to an in-memory database.
     107              :          */
     108          152 :         if(!(config->dry_run == true && config->db_primary_file_exists == true))
     109              :         {
     110          288 :                 for(int i = 0; config->paths[i]; i++)
     111              :                 {
     112              :                         // Remove unnecessary trailing slash at the end of the directory prefix
     113          144 :                         remove_trailing_slash(config->paths[i]);
     114              : 
     115          144 :                         const char *select_sql = "SELECT COUNT(*) FROM paths WHERE prefix = ?1;";
     116          144 :                         sqlite3_stmt *select_stmt = NULL;
     117              : 
     118              :                         /* First check if prefix exists */
     119          144 :                         int rc = sqlite3_prepare_v2(config->db,select_sql,-1,&select_stmt,NULL);
     120              : 
     121          144 :                         if(SQLITE_OK != rc)
     122              :                         {
     123            0 :                                 log_sqlite_error(config->db,rc,NULL,"Can't prepare select statement %s",select_sql);
     124            0 :                                 status = FAILURE;
     125              :                         }
     126              : 
     127          144 :                         if(SUCCESS == status)
     128              :                         {
     129          144 :                                 rc = sqlite3_bind_text(select_stmt,1,config->paths[i],(int)strlen(config->paths[i]),NULL);
     130              : 
     131          144 :                                 if(SQLITE_OK != rc)
     132              :                                 {
     133            0 :                                         log_sqlite_error(config->db,rc,NULL,"Error binding value in select");
     134            0 :                                         status = FAILURE;
     135              :                                 }
     136              :                         }
     137              : 
     138          144 :                         int count = 0;
     139              : 
     140          144 :                         if(SUCCESS == status)
     141              :                         {
     142          144 :                                 if(sqlite3_step(select_stmt) == SQLITE_ROW)
     143              :                                 {
     144          144 :                                         count = sqlite3_column_int(select_stmt,0);
     145              :                                 }
     146              :                         }
     147              : 
     148          144 :                         sqlite3_finalize(select_stmt);
     149              : 
     150              :                         /* Only proceed with insert if prefix doesn't exist */
     151          144 :                         if(count == 0)
     152              :                         {
     153           80 :                                 const char *insert_sql = "INSERT OR IGNORE INTO paths(prefix) VALUES(?1);";
     154           80 :                                 sqlite3_stmt *insert_stmt = NULL;
     155              : 
     156              :                                 /* Create SQL statement. Prepare to write */
     157           80 :                                 rc = sqlite3_prepare_v2(config->db,insert_sql,-1,&insert_stmt,NULL);
     158              : 
     159           80 :                                 if(SQLITE_OK != rc)
     160              :                                 {
     161            0 :                                         log_sqlite_error(config->db,rc,NULL,"Can't prepare insert statement %s",insert_sql);
     162            0 :                                         status = FAILURE;
     163              :                                 }
     164              : 
     165           80 :                                 if(SUCCESS == status)
     166              :                                 {
     167           80 :                                         rc = sqlite3_bind_text(insert_stmt,1,config->paths[i],(int)strlen(config->paths[i]),NULL);
     168              : 
     169           80 :                                         if(SQLITE_OK != rc)
     170              :                                         {
     171            0 :                                                 log_sqlite_error(config->db,rc,NULL,"Error binding value in insert");
     172            0 :                                                 status = FAILURE;
     173              :                                         }
     174              :                                 }
     175              : 
     176              :                                 /* Execute SQL statement */
     177           80 :                                 if(SUCCESS == status)
     178              :                                 {
     179           80 :                                         if(sqlite3_step(insert_stmt) != SQLITE_DONE)
     180              :                                         {
     181            0 :                                                 log_sqlite_error(config->db,rc,NULL,"Insert statement didn't return DONE");
     182            0 :                                                 status = FAILURE;
     183              :                                         }
     184              :                                 }
     185              : 
     186           80 :                                 if(SUCCESS == status && config->dry_run == false)
     187              :                                 {
     188              :                                         /* Reflect changes in global */
     189           78 :                                         config->db_primary_file_modified = true;
     190              :                                 }
     191              : 
     192           80 :                                 sqlite3_finalize(insert_stmt);
     193              :                         }
     194              : 
     195          144 :                         if(SUCCESS != status)
     196              :                         {
     197            0 :                                 break;
     198              :                         }
     199              :                 }
     200              :         }
     201              : 
     202          152 :         return(status);
     203              : }
        

Generated by: LCOV version 2.0-1