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

            Line data    Source code
       1              : #include "precizer.h"
       2              : #define DB_RUNTIME_PATHS_ID "runtime_paths_id"
       3              : #define STRINGIFY(x) #x
       4              : #define TOSTRING(x) STRINGIFY(x)
       5              : 
       6              : /**
       7              :  *
       8              :  * Initialize SQLite database
       9              :  *
      10              :  */
      11          194 : Return db_init(void)
      12              : {
      13              :         /// The status that will be passed to return() before exiting.
      14              :         /// By default, the function worked without errors.
      15          194 :         Return status = SUCCESS;
      16              : 
      17              :         /* Interrupt the function smoothly */
      18              :         /* Interrupt when Ctrl+C */
      19          194 :         if(global_interrupt_flag == true)
      20              :         {
      21            0 :                 provide(status);
      22              :         }
      23              : 
      24              :         // SQL request result
      25              :         int rc;
      26              : 
      27              :         /* Open database */
      28              : 
      29          194 :         const char *db_file_path = config->db_primary_file_path;
      30              : 
      31          194 :         if(config->sqlite_open_flag == SQL_DRY_RUN_MODE)
      32              :         {
      33            2 :                 db_file_path = ":memory:";
      34            2 :                 config->sqlite_open_flag = SQLITE_OPEN_READWRITE;
      35            2 :                 slog(TRACE,"Dry Run mode was activated. In-memory database will be used to simulate activity.\n");
      36              :         }
      37              : 
      38          194 :         if(SQLITE_OK == (rc = sqlite3_open_v2(db_file_path,&config->db,config->sqlite_open_flag,NULL)))
      39              :         {
      40          192 :                 slog(TRACE,"Successfully opened database %s\n",config->db_file_name);
      41            2 :         } else if(config->compare != true){
      42            2 :                 log_sqlite_error(config->db,
      43              :                         rc,
      44              :                         NULL,
      45              :                         "Can't open database %s",
      46            2 :                         config->db_primary_file_path);
      47            2 :                 status = FAILURE;
      48              :         }
      49              : 
      50              :         /**
      51              :          * Allow or disallow database table initialization.
      52              :          * If Dry Run mode is active, this option can be useful
      53              :          * to prevent modification of the existing database.
      54              :          *
      55              :          * Table initialization will be necessary when the database
      56              :          * is used in in-memory mode and is effectively recreated
      57              :          * during the first connection.
      58              :          *
      59              :          * Additionally, database table initialization can be used
      60              :          * to update the database schema during software upgrades.
      61              :          *
      62              :          * This describes several database management scenarios:
      63              :          *
      64              :          * 1. Table Initialization Control
      65              :          *   - Option to enable/disable table schema creation
      66              :          *   - Particularly useful with Dry Run mode to prevent schema changes
      67              :          *   - Acts as a safety mechanism for existing databases
      68              :          * 2. In-Memory Database Scenarios
      69              :          *   - When using in-memory mode, tables need initialization
      70              :          *   - Tables are recreated on first connection
      71              :          *   - No persistent storage between sessions
      72              :          * 3. Schema Migration Use Case
      73              :          *   - Can be used during software updates
      74              :          *   - Allows automatic schema updates
      75              :          *   - Supports database structure evolution with software versions
      76              :          */
      77          194 :         if(config->db_initialize_tables == true)
      78              :         {
      79           80 :                 if(SUCCESS == status)
      80              :                 {
      81              : #if 0 // Frozen multiPATH feature
      82              :                         const char *sql =
      83              :                                 "PRAGMA foreign_keys=OFF;"
      84              :                                 "PRAGMA journal_mode=DELETE;"        // Use DELETE journal to avoid WAL artifacts
      85              :                                 "PRAGMA page_size=4096;"            // Set page size to 4KB (default, but explicit for clarity)
      86              :                                 "PRAGMA cache_size=-8192;"          // Use 8MB of memory for caching (negative value = KB)
      87              :                                 "PRAGMA synchronous=NORMAL;"        // Balance speed and safety (NORMAL = fsync only for checkpoints)
      88              :                                 "PRAGMA strict = ON;"
      89              :                                 "BEGIN TRANSACTION;"
      90              :                                 "CREATE TABLE IF NOT EXISTS metadata (db_version INTEGER NOT NULL UNIQUE);"
      91              :                                 "CREATE TABLE IF NOT EXISTS files("  \
      92              :                                 "ID INTEGER PRIMARY KEY NOT NULL,"
      93              :                                 "offset INTEGER DEFAULT NULL,"
      94              :                                 "path_prefix_index INTEGER NOT NULL,"
      95              :                                 "relative_path TEXT NOT NULL,"
      96              :                                 "sha512 BLOB DEFAULT NULL,"
      97              :                                 "stat BLOB DEFAULT NULL,"
      98              :                                 "mdContext BLOB DEFAULT NULL,"
      99              :                                 "CONSTRAINT full_path UNIQUE (path_prefix_index, relative_path) ON CONFLICT FAIL);"
     100              :                                 "CREATE INDEX IF NOT EXISTS full_path_ASC ON files (path_prefix_index, relative_path ASC);"
     101              :                                 "CREATE TABLE IF NOT EXISTS paths ("
     102              :                                 "ID INTEGER PRIMARY KEY UNIQUE NOT NULL,"
     103              :                                 "prefix TEXT NOT NULL UNIQUE);"
     104              :                                 "REPLACE INTO metadata (db_version) VALUES (" TOSTRING(CURRENT_DB_VERSION) ");"
     105              :                                 "COMMIT;";
     106              : #endif
     107              : 
     108              :                         /* Full runtime path is stored in the table 'paths' */
     109           78 :                         const char *sql =
     110              :                                 "PRAGMA foreign_keys=OFF;"
     111              :                                 "PRAGMA journal_mode=DELETE;"        // Use DELETE journal to avoid WAL artifacts
     112              :                                 "PRAGMA page_size=4096;"            // Set page size to 4KB (default, but explicit for clarity)
     113              :                                 "PRAGMA cache_size=-8192;"          // Use 8MB of memory for caching (negative value = KB)
     114              :                                 "PRAGMA synchronous=NORMAL;"        // Balance speed and safety (NORMAL = fsync only for checkpoints)
     115              :                                 "PRAGMA strict = ON;"
     116              :                                 "BEGIN TRANSACTION;"
     117              :                                 "CREATE TABLE IF NOT EXISTS metadata (db_version INTEGER NOT NULL UNIQUE);"
     118              :                                 "CREATE TABLE IF NOT EXISTS files("  \
     119              :                                 "ID INTEGER PRIMARY KEY NOT NULL,"
     120              :                                 "offset INTEGER DEFAULT NULL,"
     121              :                                 "relative_path TEXT UNIQUE NOT NULL,"
     122              :                                 "sha512 BLOB DEFAULT NULL,"
     123              :                                 "stat BLOB DEFAULT NULL,"
     124              :                                 "mdContext BLOB DEFAULT NULL);"
     125              :                                 "CREATE UNIQUE INDEX IF NOT EXISTS 'TEXT_ASC' ON 'files' ('relative_path' ASC);"
     126              :                                 "CREATE TABLE IF NOT EXISTS paths ("
     127              :                                 "ID INTEGER PRIMARY KEY UNIQUE NOT NULL,"
     128              :                                 "prefix TEXT NOT NULL UNIQUE);"
     129              :                                 "REPLACE INTO metadata (db_version) VALUES (" TOSTRING(CURRENT_DB_VERSION) ");"
     130              :                                 "COMMIT;";
     131              : 
     132              :                         /* Execute SQL statement */
     133           78 :                         rc = sqlite3_exec(config->db,sql,NULL,NULL,NULL);
     134              : 
     135           78 :                         if(rc == SQLITE_OK)
     136              :                         {
     137           78 :                                 slog(TRACE,"The primary database and tables have been successfully initialized\n");
     138              :                         } else {
     139            0 :                                 log_sqlite_error(config->db,rc,NULL,"Can't execute table initialization");
     140            0 :                                 status = FAILURE;
     141              :                         }
     142              :                 }
     143              :         } else {
     144          114 :                 slog(TRACE,"The primary database and tables do not require initialization\n");
     145              :         }
     146              : 
     147          194 :         if(SUCCESS == status)
     148              :         {
     149              :                 // Tune the DB performance
     150          192 :                 const char *pragma_sql = NULL;
     151              : 
     152          192 :                 if(config->compare == true || config->dry_run == true)
     153              :                 {
     154              :                         // Read-only mode
     155           46 :                         pragma_sql =
     156              :                                 "PRAGMA synchronous=OFF;"            // Disable fsync to speed up read-only access
     157              :                                 "PRAGMA cache_size=-8192;"           // Increased cache to 8MB
     158              :                                 "PRAGMA temp_store=MEMORY;"          // Keep temporary data in RAM
     159              :                                 "PRAGMA mmap_size=30000000000;"      // Using memory-mapped I/O
     160              :                                 "PRAGMA page_size=4096;"             // Set page size to 4KB (default, but explicit for clarity)
     161              :                                 "PRAGMA locking_mode=EXCLUSIVE;"     // Hold exclusive locks for the session
     162              :                                 "PRAGMA strict=ON;";                  // Enforce STRICT table schema validation
     163              :                 } else {
     164              :                         // Read-write mode
     165          146 :                         pragma_sql =
     166              :                                 "PRAGMA journal_mode=DELETE; "       // Use DELETE journal
     167              :                                 "PRAGMA page_size=4096; "            // Set page size to 4KB (default, but explicit for clarity)
     168              :                                 "PRAGMA cache_size=-8192; "          // Use 8MB of memory for caching (negative value = KB)
     169              :                                 "PRAGMA synchronous=NORMAL; "        // Balance speed and safety (NORMAL = fsync only for checkpoints)
     170              :                                 "PRAGMA temp_store=MEMORY; "         // Store temporary tables in memory (not on disk)
     171              :                                 "PRAGMA strict=ON;"                  // Enforce STRICT table schema validation
     172              :                                 "PRAGMA locking_mode=EXCLUSIVE;"     // Hold exclusive locks for the session
     173              :                                 "PRAGMA fsync=OFF;";                 // Disables fsync() for faster writes but risks data loss on crash
     174              :                 }
     175              : 
     176              :                 // Set SQLite pragmas
     177          192 :                 rc = sqlite3_exec(config->db,pragma_sql,NULL,NULL,NULL);
     178              : 
     179          192 :                 if(rc == SQLITE_OK)
     180              :                 {
     181          192 :                         slog(TRACE,"The primary database named %s is ready for operations\n",config->db_file_name);
     182              :                 } else {
     183            0 :                         log_sqlite_error(config->db,rc,NULL,"Can't execute pragma setup");
     184            0 :                         status = FAILURE;
     185              :                 }
     186              :         }
     187              : 
     188          194 :         if(SUCCESS == status)
     189              :         {
     190          192 :                 if(config->compare != true)
     191              :                 {
     192          156 :                         const char *db_runtime_paths = "ATTACH DATABASE ':memory:' AS " DB_RUNTIME_PATHS_ID ";"
     193              :                                 "CREATE TABLE if not exists runtime_paths_id.the_path_id_does_not_exists"
     194              :                                 "(path_id INTEGER UNIQUE NOT NULL);";
     195              : 
     196          156 :                         rc = sqlite3_exec(config->db,db_runtime_paths,NULL,NULL,NULL);
     197              : 
     198          156 :                         if(rc == SQLITE_OK)
     199              :                         {
     200          156 :                                 slog(TRACE,"The in-memory %s database successfully attached to the primary database %s\n",DB_RUNTIME_PATHS_ID,config->db_file_name);
     201              :                         } else {
     202            0 :                                 log_sqlite_error(config->db,rc,NULL,"Can't execute runtime paths attach");
     203            0 :                                 status = FAILURE;
     204              :                         }
     205              :                 }
     206              :         }
     207              : 
     208          194 :         slog(TRACE,"Database initialization process completed\n");
     209              : 
     210          194 :         provide(status);
     211              : }
        

Generated by: LCOV version 2.0-1