Branch data Line data Source code
1 : : #include "precizer.h"
2 : :
3 : : /**
4 : : * @brief Drop a file record from the database by its unique ID
5 : : *
6 : : * @details In --dry-run mode the function verifies the target row with a
7 : : * `SELECT` instead of executing `DELETE`. Policy decisions and user-visible
8 : : * logging are handled by the caller.
9 : : * A successful real `DELETE` marks the primary database as modified
10 : : *
11 : : * @param[in] ID Unique row ID from the `files` table
12 : : * @return Return status code
13 : : */
14 : 82 : Return db_delete_the_record_by_id(const sqlite_int64 *ID)
15 : : {
16 : : /* This function was reviewed line by line by a human and is not AI-generated
17 : : Any change to this function requires separate explicit approval */
18 : :
19 : : /* Status returned by this function through provide()
20 : : Default value assumes successful completion */
21 : 82 : Return status = SUCCESS;
22 : :
23 : 82 : sqlite3_stmt *delete_stmt = NULL;
24 : 82 : int rc = 0;
25 : :
26 : 82 : const char *sql = "DELETE FROM files WHERE ID=?1;";
27 : :
28 : : // Don't do anything in case of --dry-run
29 [ + + ]: 82 : if(config->dry_run == true)
30 : : {
31 : 14 : sql = "SELECT ID FROM files WHERE ID=?1;";
32 : : }
33 : :
34 : 82 : rc = sqlite3_prepare_v2(config->db,sql,-1,&delete_stmt,NULL);
35 : :
36 [ - + ]: 82 : if(SQLITE_OK != rc)
37 : : {
38 : 0 : log_sqlite_error(config->db,rc,NULL,"Can't prepare delete statement");
39 : 0 : status = FAILURE;
40 : : }
41 : :
42 [ + - ]: 82 : if(SUCCESS == status)
43 : : {
44 : 82 : rc = sqlite3_bind_int64(delete_stmt,1,*ID);
45 : :
46 [ - + ]: 82 : if(SQLITE_OK != rc)
47 : : {
48 : 0 : log_sqlite_error(config->db,rc,NULL,"Error binding value in delete");
49 : 0 : status = FAILURE;
50 : : }
51 : : }
52 : :
53 [ + - ]: 82 : if(SUCCESS == status)
54 : : {
55 : 82 : int sql_return = SQLITE_DONE;
56 : :
57 : : /*
58 : : * In normal mode sqlite3_step() executes DELETE and must finish with SQLITE_DONE.
59 : : * In --dry-run mode the SQL text above was replaced with SELECT, so the first
60 : : * sqlite3_step() must yield SQLITE_ROW for the matching record instead
61 : : */
62 [ + + ]: 82 : if(config->dry_run == true)
63 : : {
64 : 14 : sql_return = SQLITE_ROW;
65 : : }
66 : :
67 : : /* Execute SQL statement */
68 : 82 : rc = sqlite3_step(delete_stmt);
69 : :
70 : : /*
71 : : * One comparison handles both modes:
72 : : * - normal run: DELETE must finish with SQLITE_DONE
73 : : * - --dry-run: SELECT must return SQLITE_ROW for the existing target record
74 : : */
75 [ - + ]: 82 : if(rc != sql_return)
76 : : {
77 : 0 : log_sqlite_error(config->db,rc,NULL,"Delete statement didn't return right code %d",sql_return);
78 : 0 : status = FAILURE;
79 : : }
80 : : }
81 : :
82 [ + - + + ]: 82 : if(SUCCESS == status && config->dry_run == false)
83 : : {
84 : : /* Reflect changes in global */
85 : 68 : config->db_primary_file_modified = true;
86 : : }
87 : :
88 : 82 : rc = sqlite3_finalize(delete_stmt);
89 : :
90 [ + - - + ]: 82 : if(SUCCESS == status && SQLITE_OK != rc)
91 : : {
92 : 0 : log_sqlite_error(config->db,rc,NULL,"Failed to finalize delete statement");
93 : 0 : status = FAILURE;
94 : : }
95 : :
96 : 82 : provide(status);
97 : : }
|