LCOV - code coverage report
Current view: top level - src - db_compare.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 84.1 % 164 138
Test Date: 2026-03-31 13:51:38 Functions: 100.0 % 5 5
Branches: 78.0 % 164 128

             Branch data     Line data    Source code
       1                 :             : #include "precizer.h"
       2                 :             : 
       3                 :             : /**
       4                 :             :  * @brief Composes an SQL ATTACH DATABASE query string.
       5                 :             :  *
       6                 :             :  * This function generates an SQL query string to attach a database with a specified path and number.
       7                 :             :  *
       8                 :             :  * @param[out] sql Pointer to a string that will hold the generated SQL query.
       9                 :             :  * @param[in] db_path Path to the database file to be attached.
      10                 :             :  * @param[in] db_num Database number (1 or 2) used in the query.
      11                 :             :  * @return Return structure indicating the operation status.
      12                 :             :  */
      13                 :         224 : static Return compose_sql(
      14                 :             :         char       **sql,
      15                 :             :         const char *db_path,
      16                 :             :         int        db_num)
      17                 :             : {
      18                 :             :         /* Status returned by this function through provide()
      19                 :             :            Default value assumes successful completion */
      20                 :         224 :         Return status = SUCCESS;
      21                 :         224 :         create(char,wrapped_db_path);
      22                 :             : 
      23   [ +  -  -  + ]:         224 :         run(db_sql_wrap_string(wrapped_db_path,db_path));
      24                 :             : 
      25   [ +  -  -  + ]:         224 :         if(SUCCESS == status && asprintf(sql,"ATTACH DATABASE %s as db%d;",getcstring(wrapped_db_path),db_num) == -1)
      26                 :             :         {
      27                 :           0 :                 status = FAILURE;
      28                 :           0 :                 report("Memory allocation failed for SQL query string");
      29                 :             :         }
      30                 :             : 
      31                 :         224 :         del(wrapped_db_path);
      32                 :             : 
      33                 :         224 :         provide(status);
      34                 :             : }
      35                 :             : 
      36                 :             : /**
      37                 :             :  * @brief Attaches a secondary database to the primary database connection.
      38                 :             :  *
      39                 :             :  * This function attaches a secondary database (specified by its index in the configuration)
      40                 :             :  * to the primary SQLite database connection using the ATTACH DATABASE command.
      41                 :             :  *
      42                 :             :  * @param[in] db_A Index of the database path in the configuration array.
      43                 :             :  * @param[in] db_B Database number (1 or 2) to be used in the ATTACH DATABASE command.
      44                 :             :  * @return Return structure indicating the operation status.
      45                 :             :  */
      46                 :         224 : static Return db_attach(
      47                 :             :         int db_A,
      48                 :             :         int db_B)
      49                 :             : {
      50                 :             :         /* Status returned by this function through provide()
      51                 :             :            Default value assumes successful completion */
      52                 :         224 :         Return status = SUCCESS;
      53                 :             : 
      54                 :         224 :         char *select_sql = NULL;
      55                 :             : 
      56   [ +  -  -  + ]:         224 :         run(compose_sql(&select_sql,config->db_file_paths[db_A],db_B));
      57                 :             : 
      58         [ +  - ]:         224 :         if(SUCCESS == status)
      59                 :             :         {
      60                 :         224 :                 int rc = sqlite3_exec(config->db,select_sql,NULL,NULL,NULL);
      61                 :             : 
      62         [ -  + ]:         224 :                 if(rc!= SQLITE_OK)
      63                 :             :                 {
      64                 :           0 :                         log_sqlite_error(config->db,rc,NULL,"Can't execute");
      65                 :           0 :                         status = FAILURE;
      66                 :             :                 }
      67                 :             :         }
      68                 :             : 
      69                 :         224 :         free(select_sql);
      70                 :             : 
      71                 :         224 :         provide(status);
      72                 :             : }
      73                 :             : 
      74                 :             : /**
      75                 :             :  * @brief Detach database by alias
      76                 :             :  *
      77                 :             :  * @param[in] db_alias Attached database alias name
      78                 :             :  * @return Return status code
      79                 :             :  */
      80                 :         224 : static Return db_detach(const char *db_alias)
      81                 :             : {
      82                 :             :         /* Status returned by this function through provide()
      83                 :             :            Default value assumes successful completion */
      84                 :         224 :         Return status = SUCCESS;
      85                 :             : 
      86                 :         224 :         sqlite3_stmt *stmt = NULL;
      87                 :             : 
      88                 :         224 :         const char *sql = "DETACH DATABASE ?1;";
      89                 :             : 
      90                 :         224 :         int rc = sqlite3_prepare_v2(config->db,sql,-1,&stmt,NULL);
      91                 :             : 
      92         [ -  + ]:         224 :         if(SQLITE_OK != rc)
      93                 :             :         {
      94                 :           0 :                 log_sqlite_error(config->db,rc,NULL,"Failed to prepare detach statement");
      95                 :           0 :                 status = FAILURE;
      96                 :             :         }
      97                 :             : 
      98         [ +  - ]:         224 :         if(SUCCESS == status)
      99                 :             :         {
     100                 :         224 :                 rc = sqlite3_bind_text(stmt,1,db_alias,-1,SQLITE_STATIC);
     101                 :             : 
     102         [ -  + ]:         224 :                 if(SQLITE_OK != rc)
     103                 :             :                 {
     104                 :           0 :                         log_sqlite_error(config->db,rc,NULL,"Failed to bind database alias in detach");
     105                 :           0 :                         status = FAILURE;
     106                 :             :                 }
     107                 :             :         }
     108                 :             : 
     109         [ +  - ]:         224 :         if(SUCCESS == status)
     110                 :             :         {
     111                 :         224 :                 rc = sqlite3_step(stmt);
     112                 :             : 
     113         [ -  + ]:         224 :                 if(SQLITE_DONE != rc)
     114                 :             :                 {
     115                 :           0 :                         log_sqlite_error(config->db,rc,NULL,"Detach statement didn't return DONE");
     116                 :           0 :                         status = FAILURE;
     117                 :             :                 }
     118                 :             :         }
     119                 :             : 
     120         [ +  - ]:         224 :         if(stmt != NULL)
     121                 :             :         {
     122                 :         224 :                 sqlite3_finalize(stmt);
     123                 :             :         }
     124                 :             : 
     125                 :         224 :         provide(status);
     126                 :             : }
     127                 :             : 
     128                 :             : /**
     129                 :             :  * @brief Run one compare query and print only the paths that pass output filters
     130                 :             :  *
     131                 :             :  * Executes the supplied comparison query, applies the shared --include/--ignore
     132                 :             :  * decision before reporting each row, and reports only visible relative paths.
     133                 :             :  * Only visible paths contribute to category state, so compare summaries and
     134                 :             :  * equality messages are evaluated against the filtered scope. The category
     135                 :             :  * heading is emitted only before the first visible path and stays visible in
     136                 :             :  * `--silent` only when `show_headings_in_silent` enables it
     137                 :             :  *
     138                 :             :  * @param[in] compare_sql SQL query that returns relative paths for one compare category
     139                 :             :  * @param[out] differences_found Set to `true` after the first visible path is printed
     140                 :             :  *             so hidden rows stay outside the reported comparison scope
     141                 :             :  * @param[in] show_headings_in_silent True to keep the category heading visible in `--silent`
     142                 :             :  * @param[in] heading_format Heading format string with two `%s` database-name slots
     143                 :             :  * @param[in] db_A_name First database name for the heading
     144                 :             :  * @param[in] db_B_name Second database name for the heading
     145                 :             :  * @return Return structure indicating the operation status
     146                 :             :  */
     147                 :         266 : static Return db_report_category(
     148                 :             :         const char *compare_sql,
     149                 :             :         bool       *differences_found,
     150                 :             :         const bool show_headings_in_silent,
     151                 :             :         const char *heading_format,
     152                 :             :         const char *db_A_name,
     153                 :             :         const char *db_B_name)
     154                 :             : {
     155                 :             :         /* Status returned by this function through provide()
     156                 :             :            Default value assumes successful completion */
     157                 :         266 :         Return status = SUCCESS;
     158                 :             : 
     159                 :         266 :         sqlite3_stmt *select_stmt = NULL;
     160                 :             : 
     161                 :         266 :         int rc = sqlite3_prepare_v2(config->db,compare_sql,-1,&select_stmt,NULL);
     162                 :             : 
     163         [ -  + ]:         266 :         if(SQLITE_OK != rc)
     164                 :             :         {
     165                 :           0 :                 log_sqlite_error(config->db,rc,NULL,"Can't prepare select statement");
     166                 :           0 :                 status = FAILURE;
     167                 :             :         }
     168                 :             : 
     169         [ +  - ]:         266 :         if(SUCCESS == status)
     170                 :             :         {
     171                 :         266 :                 bool first_visible_path = true;
     172                 :             : 
     173         [ +  + ]:         426 :                 while(SQLITE_ROW == (rc = sqlite3_step(select_stmt)))
     174                 :             :                 {
     175                 :             :                         // Interrupt the loop smoothly
     176                 :             :                         // Interrupt when Ctrl+C
     177         [ -  + ]:         160 :                         if(global_interrupt_flag == true)
     178                 :             :                         {
     179                 :           0 :                                 break;
     180                 :             :                         }
     181                 :             : 
     182                 :         160 :                         const unsigned char *relative_path = sqlite3_column_text(select_stmt,0);
     183                 :             : 
     184         [ -  + ]:         160 :                         if(relative_path == NULL)
     185                 :             :                         {
     186                 :           0 :                                 rc = sqlite3_errcode(config->db);
     187                 :           0 :                                 log_sqlite_error(config->db,rc,NULL,"Failed to read relative path from select result");
     188                 :           0 :                                 status = FAILURE;
     189                 :           0 :                                 break;
     190                 :             :                         }
     191                 :             : 
     192                 :         160 :                         bool ignore = false;
     193                 :             : 
     194                 :         160 :                         status = match_include_ignore((const char *)relative_path,
     195                 :             :                                 NULL,
     196                 :             :                                 &ignore);
     197                 :             : 
     198         [ -  + ]:         160 :                         if(SUCCESS != status)
     199                 :             :                         {
     200                 :           0 :                                 break;
     201                 :             :                         }
     202                 :             : 
     203         [ +  + ]:         160 :                         if(ignore == true)
     204                 :             :                         {
     205                 :          32 :                                 continue;
     206                 :             :                         }
     207                 :             : 
     208         [ +  + ]:         128 :                         if(first_visible_path == true)
     209                 :             :                         {
     210                 :         112 :                                 first_visible_path = false;
     211                 :             : 
     212                 :             :                                 // Outside --silent the heading is always shown
     213                 :             :                                 // In --silent it stays only when multiple compare categories can mix together in one output
     214   [ +  +  +  + ]:         112 :                                 if((rational_logger_mode & SILENT) == 0 || show_headings_in_silent == true)
     215                 :             :                                 {
     216                 :         106 :                                         slog(EVERY|VISIBLE_IN_SILENT,heading_format,db_A_name,db_B_name);
     217                 :             :                                 }
     218                 :             :                         }
     219                 :             : 
     220                 :         128 :                         *differences_found = true;
     221                 :         128 :                         slog(EVERY|UNDECOR|VISIBLE_IN_SILENT,"%s\n",relative_path);
     222                 :             :                 }
     223                 :             : 
     224   [ +  -  +  -  :         266 :                 if(SUCCESS == status && global_interrupt_flag == false && SQLITE_DONE != rc)
                   -  + ]
     225                 :             :                 {
     226                 :           0 :                         log_sqlite_error(config->db,rc,NULL,"Select statement didn't finish with DONE");
     227                 :           0 :                         status = FAILURE;
     228                 :             :                 }
     229                 :             :         }
     230                 :             : 
     231         [ +  - ]:         266 :         if(select_stmt != NULL)
     232                 :             :         {
     233                 :         266 :                 rc = sqlite3_finalize(select_stmt);
     234                 :             : 
     235         [ -  + ]:         266 :                 if(SQLITE_OK != rc)
     236                 :             :                 {
     237                 :           0 :                         log_sqlite_error(config->db,rc,NULL,"Failed to finalize SQLite statement");
     238                 :           0 :                         status = FAILURE;
     239                 :             :                 } else {
     240                 :         266 :                         select_stmt = NULL;
     241                 :             :                 }
     242                 :             :         }
     243                 :             : 
     244                 :         266 :         provide(status);
     245                 :             : }
     246                 :             : 
     247                 :             : /**
     248                 :             :  * @brief Compare two databases selected in the global config
     249                 :             :  *
     250                 :             :  * @details Attaches both databases, reports requested difference categories,
     251                 :             :  * and prints summary lines for missing paths and checksum mismatches. The
     252                 :             :  * comparison scope can be limited with `--compare-filter` and further narrowed
     253                 :             :  * by `--ignore` and `--include`; without filters the function checks
     254                 :             :  * first-source paths, second-source paths, and SHA512 mismatches
     255                 :             :  *
     256                 :             :  * @return Return status code
     257                 :             :  */
     258                 :         389 : Return db_compare(void)
     259                 :             : {
     260                 :             :         /* Status returned by this function through provide()
     261                 :             :            Default value assumes successful completion */
     262                 :         389 :         Return status = SUCCESS;
     263                 :             : 
     264                 :         389 :         bool attached_db1 = false;
     265                 :         389 :         bool attached_db2 = false;
     266                 :             : 
     267                 :             :         /* Interrupt the function smoothly */
     268                 :             :         /* Interrupt when Ctrl+C */
     269         [ -  + ]:         389 :         if(global_interrupt_flag == true)
     270                 :             :         {
     271                 :           0 :                 provide(status);
     272                 :             :         }
     273                 :             : 
     274                 :             :         /* Skip if comparison mode is not enabled */
     275         [ +  + ]:         389 :         if(config->compare != true)
     276                 :             :         {
     277                 :         271 :                 slog(TRACE,"Database comparison mode is not enabled. Skipping comparison\n");
     278                 :         271 :                 provide(status);
     279                 :             :         }
     280                 :             : 
     281                 :         118 :         slog(EVERY,"The comparison of %s and %s databases is starting…\n",config->db_file_names[0],config->db_file_names[1]);
     282                 :             : 
     283                 :             :         /* Validate database paths */
     284         [ +  + ]:         346 :         for(int i = 0; config->db_file_paths[i]; i++)
     285                 :             :         {
     286         [ -  + ]:         234 :                 if(NOT_FOUND == file_availability(config->db_file_paths[i],NULL,SHOULD_BE_A_FILE))
     287                 :             :                 {
     288                 :           0 :                         slog(ERROR,"The database file %s is either inaccessible or not a valid file\n",
     289                 :             :                                 config->db_file_paths[i]);
     290                 :           0 :                         status = FAILURE;
     291                 :           0 :                         break;
     292                 :             :                 }
     293                 :             : 
     294         [ +  - ]:         234 :                 if(SUCCESS == status)
     295                 :             :                 {
     296                 :             :                         /*
     297                 :             :                          * Validate the integrity of the database file
     298                 :             :                          */
     299                 :         234 :                         status = db_integrity_check(config->db_file_paths[i]);
     300                 :             : 
     301         [ +  + ]:         234 :                         if(SUCCESS != status)
     302                 :             :                         {
     303                 :           6 :                                 break;
     304                 :             :                         }
     305                 :             :                 }
     306                 :             :         }
     307                 :             : 
     308                 :             :         /* Attach databases */
     309         [ +  + ]:         118 :         if(SUCCESS == status)
     310                 :             :         {
     311                 :             :                 // Attach the database 1
     312                 :         112 :                 status = db_attach(0,1);
     313                 :             : 
     314         [ +  - ]:         112 :                 if(SUCCESS == status)
     315                 :             :                 {
     316                 :         112 :                         attached_db1 = true;
     317                 :             :                 }
     318                 :             :         }
     319                 :             : 
     320         [ +  + ]:         118 :         if(SUCCESS == status)
     321                 :             :         {
     322                 :             :                 // Attach the database 2
     323                 :         112 :                 status = db_attach(1,2);
     324                 :             : 
     325         [ +  - ]:         112 :                 if(SUCCESS == status)
     326                 :             :                 {
     327                 :         112 :                         attached_db2 = true;
     328                 :             :                 }
     329                 :             :         }
     330                 :             : 
     331                 :             :         /* SQL queries for comparison */
     332                 :         118 :         const char *compare_A_sql = "SELECT a.relative_path "
     333                 :             :                 "FROM db2.files AS a "
     334                 :             :                 "LEFT JOIN db1.files AS b on b.relative_path = a.relative_path "
     335                 :             :                 "WHERE b.relative_path IS NULL "
     336                 :             :                 "ORDER BY a.relative_path ASC;";
     337                 :             : 
     338                 :         118 :         const char *compare_B_sql = "SELECT a.relative_path "
     339                 :             :                 "FROM db1.files AS a "
     340                 :             :                 "LEFT join db2.files AS b on b.relative_path = a.relative_path "
     341                 :             :                 "WHERE b.relative_path IS NULL "
     342                 :             :                 "ORDER BY a.relative_path ASC;";
     343                 :             : 
     344                 :             :         // True when user provided at least one --compare-filter option.
     345                 :             :         // False means default compare mode: all three categories are enabled.
     346                 :         118 :         const bool filter_specified = config->compare_filter != CF_NONE_SPECIFIED;
     347                 :             : 
     348                 :             :         // Enables "first-source" category:
     349                 :             :         // show paths that exist in db1 but are missing in db2.
     350                 :             :         // This category is active either explicitly by filter or by default mode.
     351                 :         236 :         const bool check_first_source = (config->compare_filter & CF_FIRST_SOURCE)
     352   [ +  +  +  + ]:         118 :                 || filter_specified == false;
     353                 :             : 
     354                 :             :         // Enables "second-source" category:
     355                 :             :         // show paths that exist in db2 but are missing in db1.
     356                 :             :         // This category is active either explicitly by filter or by default mode.
     357                 :         236 :         const bool check_second_source = (config->compare_filter & CF_SECOND_SOURCE)
     358   [ +  +  +  + ]:         118 :                 || filter_specified == false;
     359                 :             : 
     360                 :             :         // Enables checksum verification category for common relative paths.
     361                 :             :         // Active either explicitly by checksum filter or by default mode.
     362                 :         236 :         const bool verify_checksum_consistency = (config->compare_filter & CF_CHECKSUM_MISMATCH)
     363   [ +  +  +  + ]:         118 :                 || filter_specified == false;
     364                 :             : 
     365                 :             :         // Counts enabled compare categories so silent mode can decide whether headings are needed
     366                 :         118 :         unsigned int active_compare_categories = 0u;
     367                 :             : 
     368         [ +  + ]:         118 :         if(check_first_source == true)
     369                 :             :         {
     370                 :          96 :                 active_compare_categories++;
     371                 :             :         }
     372                 :             : 
     373         [ +  + ]:         118 :         if(check_second_source == true)
     374                 :             :         {
     375                 :          96 :                 active_compare_categories++;
     376                 :             :         }
     377                 :             : 
     378         [ +  + ]:         118 :         if(verify_checksum_consistency == true)
     379                 :             :         {
     380                 :          92 :                 active_compare_categories++;
     381                 :             :         }
     382                 :             : 
     383                 :             :         // Keeps category headings visible only when silent output can mix multiple categories
     384                 :         118 :         const bool show_headings_in_silent = active_compare_categories > 1u;
     385                 :             : 
     386                 :             :         // Comparison result flags grouped in one place for summary evaluation
     387                 :         118 :         bool first_source_differences_found = false;
     388                 :         118 :         bool second_source_differences_found = false;
     389                 :         118 :         bool checksum_mismatches_found = false;
     390                 :             : 
     391                 :             :         /* Compare files existence between databases */
     392         [ +  + ]:         118 :         if(check_first_source == true)
     393                 :             :         {
     394   [ +  +  -  + ]:          96 :                 run(db_report_category(compare_B_sql,
     395                 :             :                         &first_source_differences_found,
     396                 :             :                         show_headings_in_silent,
     397                 :             :                         BOLD "These files are no longer in the %s but still exist in the %s" RESET "\n",
     398                 :             :                         config->db_file_names[1],
     399                 :             :                         config->db_file_names[0]));
     400                 :             :         }
     401                 :             : 
     402         [ +  + ]:         118 :         if(check_second_source == true)
     403                 :             :         {
     404   [ +  +  -  + ]:          96 :                 run(db_report_category(compare_A_sql,
     405                 :             :                         &second_source_differences_found,
     406                 :             :                         show_headings_in_silent,
     407                 :             :                         BOLD "These files are no longer in the %s but still exist in the %s" RESET "\n",
     408                 :             :                         config->db_file_names[0],
     409                 :             :                         config->db_file_names[1]));
     410                 :             :         }
     411                 :             : 
     412                 :             : #if 0
     413                 :             :         // Old multiPATH solutions
     414                 :             :         const char *compare_checksums_sql = "select a.relative_path from db2.files a inner join db1.files b"
     415                 :             :                 " on b.relative_path = a.relative_path "
     416                 :             :                 " and b.sha512 is not a.sha512"
     417                 :             :                 " order by a.relative_path asc;";
     418                 :             : 
     419                 :             :         const char *compare_checksums_sql = "SELECT p.path,f1.relative_path "
     420                 :             :                 "FROM db1.files AS f1 "
     421                 :             :                 "JOIN db1.paths AS p ON f1.path_prefix_index = p.ID "
     422                 :             :                 "JOIN db2.files AS f2 ON f1.relative_path = f2.relative_path "
     423                 :             :                 "JOIN db2.paths AS p2 ON f2.path_prefix_index = p2.ID "
     424                 :             :                 "WHERE f1.sha512 IS NOT f2.sha512 AND p.path = p2.path "
     425                 :             :                 "ORDER BY p.path,f1.relative_path ASC;";
     426                 :             : #else
     427                 :             :         // One PATH solution
     428                 :         118 :         const char *compare_checksums_sql = "SELECT a.relative_path "
     429                 :             :                 "FROM db2.files AS a "
     430                 :             :                 "INNER JOIN db1.files AS b ON b.relative_path = a.relative_path "
     431                 :             :                 "WHERE b.sha512 IS NOT a.sha512 "
     432                 :             :                 "ORDER BY a.relative_path ASC;";
     433                 :             : #endif
     434                 :             : 
     435         [ +  + ]:         118 :         if(verify_checksum_consistency == true)
     436                 :             :         {
     437   [ +  +  -  + ]:          92 :                 run(db_report_category(compare_checksums_sql,
     438                 :             :                         &checksum_mismatches_found,
     439                 :             :                         show_headings_in_silent,
     440                 :             :                         BOLD "The SHA512 checksums of these files do not match between %s and %s" RESET "\n",
     441                 :             :                         config->db_file_names[0],
     442                 :             :                         config->db_file_names[1]));
     443                 :             :         }
     444                 :             : 
     445                 :             :         /* Cleanup */
     446         [ +  + ]:         118 :         if(attached_db1 == true)
     447                 :             :         {
     448   [ -  +  -  + ]:         112 :                 call(db_detach("db1"));
     449                 :             :         }
     450                 :             : 
     451         [ +  + ]:         118 :         if(attached_db2 == true)
     452                 :             :         {
     453   [ -  +  -  + ]:         112 :                 call(db_detach("db2"));
     454                 :             :         }
     455                 :             : 
     456                 :             :         /* Output results */
     457         [ +  + ]:         118 :         if(SUCCESS == status)
     458                 :             :         {
     459                 :         112 :                 const bool full_compare_scope = check_first_source == true
     460         [ +  + ]:          90 :                         && check_second_source == true
     461   [ +  +  +  + ]:         202 :                         && verify_checksum_consistency == true;
     462                 :             : 
     463         [ +  + ]:         112 :                 if(full_compare_scope == true
     464         [ +  + ]:          70 :                         && first_source_differences_found == false
     465         [ +  + ]:          50 :                         && second_source_differences_found == false
     466         [ +  + ]:          36 :                         && checksum_mismatches_found == false)
     467                 :             :                 {
     468                 :          28 :                         slog(EVERY,BOLD "All files are identical against %s and %s" RESET "\n",
     469                 :             :                                 config->db_file_names[0],
     470                 :             :                                 config->db_file_names[1]);
     471                 :             : 
     472         [ +  + ]:          84 :                 } else if(full_compare_scope == false){
     473                 :             : 
     474         [ +  + ]:          42 :                         if(check_first_source == true
     475         [ +  + ]:          20 :                                 && first_source_differences_found == false)
     476                 :             :                         {
     477                 :           8 :                                 slog(EVERY,BOLD "No first-source differences found between %s and %s" RESET "\n",
     478                 :             :                                         config->db_file_names[0],
     479                 :             :                                         config->db_file_names[1]);
     480                 :             :                         }
     481                 :             : 
     482         [ +  + ]:          42 :                         if(check_second_source == true
     483         [ +  + ]:          20 :                                 && second_source_differences_found == false)
     484                 :             :                         {
     485                 :           8 :                                 slog(EVERY,BOLD "No second-source differences found between %s and %s" RESET "\n",
     486                 :             :                                         config->db_file_names[0],
     487                 :             :                                         config->db_file_names[1]);
     488                 :             :                         }
     489                 :             :                 }
     490                 :             : 
     491   [ +  +  +  + ]:         112 :                 if(verify_checksum_consistency == true && checksum_mismatches_found == false)
     492                 :             :                 {
     493                 :          46 :                         slog(EVERY,BOLD "All SHA512 checksums of files are identical against %s and %s" RESET "\n",
     494                 :             :                                 config->db_file_names[0],
     495                 :             :                                 config->db_file_names[1]);
     496                 :             :                 }
     497                 :             : 
     498         [ +  + ]:         112 :                 if(full_compare_scope == true
     499         [ +  + ]:          70 :                         && first_source_differences_found == false
     500         [ +  + ]:          50 :                         && second_source_differences_found == false
     501         [ +  + ]:          36 :                         && checksum_mismatches_found == false)
     502                 :             :                 {
     503                 :          28 :                         slog(EVERY,BOLD "The databases %s and %s are absolutely equal" RESET "\n",
     504                 :             :                                 config->db_file_names[0],
     505                 :             :                                 config->db_file_names[1]);
     506                 :             :                 }
     507                 :             :         }
     508                 :             : 
     509                 :         118 :         slog(EVERY,"Comparison of %s and %s databases is complete\n",
     510                 :             :                 config->db_file_names[0],
     511                 :             :                 config->db_file_names[1]);
     512                 :             : 
     513                 :         118 :         provide(status);
     514                 :             : }
        

Generated by: LCOV version 2.0-1