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 : : }
|