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-03-01 04:31:48 Functions: 100.0 % 1 1
Branches: 64.0 % 50 32

             Branch data     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                 :         301 : Return db_save_prefixes(void)
      50                 :             : {
      51                 :             :         /* Status returned by this function through provide()
      52                 :             :            Default value assumes successful completion */
      53                 :         301 :         Return status = SUCCESS;
      54                 :             : 
      55                 :             :         /* Interrupt the function smoothly */
      56                 :             :         /* Interrupt when Ctrl+C */
      57         [ -  + ]:         301 :         if(global_interrupt_flag == true)
      58                 :             :         {
      59                 :           0 :                 provide(status);
      60                 :             :         }
      61                 :             : 
      62                 :             :         /* Skip in comparison mode */
      63         [ +  + ]:         301 :         if(config->compare == true)
      64                 :             :         {
      65                 :          70 :                 return(status);
      66                 :             :         }
      67                 :             : 
      68   [ +  +  +  - ]:         231 :         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 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   [ +  +  +  + ]:         231 :         if(!(config->dry_run == true && config->db_primary_file_exists == true))
     109                 :             :         {
     110         [ +  + ]:         442 :                 for(int i = 0; config->paths[i]; i++)
     111                 :             :                 {
     112                 :             :                         // Remove unnecessary trailing slash at the end of the directory prefix
     113                 :         221 :                         remove_trailing_slash(config->paths[i]);
     114                 :             : 
     115                 :         221 :                         const char *select_sql = "SELECT COUNT(*) FROM paths WHERE prefix = ?1;";
     116                 :         221 :                         sqlite3_stmt *select_stmt = NULL;
     117                 :             : 
     118                 :             :                         /* First check if prefix exists */
     119                 :         221 :                         int rc = sqlite3_prepare_v2(config->db,select_sql,-1,&select_stmt,NULL);
     120                 :             : 
     121         [ -  + ]:         221 :                         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         [ +  - ]:         221 :                         if(SUCCESS == status)
     128                 :             :                         {
     129                 :         221 :                                 rc = sqlite3_bind_text(select_stmt,1,config->paths[i],(int)strlen(config->paths[i]),NULL);
     130                 :             : 
     131         [ -  + ]:         221 :                                 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                 :         221 :                         int count = 0;
     139                 :             : 
     140         [ +  - ]:         221 :                         if(SUCCESS == status)
     141                 :             :                         {
     142         [ +  - ]:         221 :                                 if(sqlite3_step(select_stmt) == SQLITE_ROW)
     143                 :             :                                 {
     144                 :         221 :                                         count = sqlite3_column_int(select_stmt,0);
     145                 :             :                                 }
     146                 :             :                         }
     147                 :             : 
     148                 :         221 :                         sqlite3_finalize(select_stmt);
     149                 :             : 
     150                 :             :                         /* Only proceed with insert if prefix doesn't exist */
     151         [ +  + ]:         221 :                         if(count == 0)
     152                 :             :                         {
     153                 :         127 :                                 const char *insert_sql = "INSERT OR IGNORE INTO paths(prefix) VALUES(?1);";
     154                 :         127 :                                 sqlite3_stmt *insert_stmt = NULL;
     155                 :             : 
     156                 :             :                                 /* Create SQL statement. Prepare to write */
     157                 :         127 :                                 rc = sqlite3_prepare_v2(config->db,insert_sql,-1,&insert_stmt,NULL);
     158                 :             : 
     159         [ -  + ]:         127 :                                 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         [ +  - ]:         127 :                                 if(SUCCESS == status)
     166                 :             :                                 {
     167                 :         127 :                                         rc = sqlite3_bind_text(insert_stmt,1,config->paths[i],(int)strlen(config->paths[i]),NULL);
     168                 :             : 
     169         [ -  + ]:         127 :                                         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         [ +  - ]:         127 :                                 if(SUCCESS == status)
     178                 :             :                                 {
     179         [ -  + ]:         127 :                                         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   [ +  -  +  + ]:         127 :                                 if(SUCCESS == status && config->dry_run == false)
     187                 :             :                                 {
     188                 :             :                                         /* Reflect changes in global */
     189                 :         121 :                                         config->db_primary_file_modified = true;
     190                 :             :                                 }
     191                 :             : 
     192                 :         127 :                                 sqlite3_finalize(insert_stmt);
     193                 :             :                         }
     194                 :             : 
     195         [ -  + ]:         221 :                         if(SUCCESS != status)
     196                 :             :                         {
     197                 :           0 :                                 break;
     198                 :             :                         }
     199                 :             :                 }
     200                 :             :         }
     201                 :             : 
     202                 :         231 :         return(status);
     203                 :             : }
        

Generated by: LCOV version 2.0-1