Branch data Line data Source code
1 : : /**
2 : : * @file db_specify_version.c
3 : : * @brief Store database schema-version metadata
4 : : */
5 : :
6 : : #include "precizer.h"
7 : :
8 : : /**
9 : : * @brief Store a database version in the metadata table
10 : : *
11 : : * @details Opens the target database in read-write mode, clears the metadata
12 : : * table, writes @p version as the current schema version, and commits the
13 : : * update in one transaction. The function skips work after an interrupt and in
14 : : * dry-run mode. When the primary database is updated, the global modification
15 : : * flag is set so final consistency checks know that a database write happened
16 : : *
17 : : * @param[in] db_file_path Path to the SQLite database file
18 : : * @param[in] version Version number to write into `metadata.db_version`
19 : : *
20 : : * @return Return status codes:
21 : : * - SUCCESS: Version set successfully
22 : : * - FAILURE: Database error or invalid parameters
23 : : */
24 : 30 : Return db_specify_version(
25 : : const char *db_file_path,
26 : : int version)
27 : : {
28 : : /* Status returned by this function through provide()
29 : : Default value assumes successful completion */
30 : 30 : Return status = SUCCESS;
31 : 30 : sqlite3 *db = NULL;
32 : 30 : sqlite3_stmt *stmt = NULL;
33 : 30 : bool db_file_modified = false;
34 : 30 : int rc = SQLITE_OK;
35 : :
36 : : /* Validate input parameters */
37 [ - + ]: 30 : if(db_file_path == NULL)
38 : : {
39 : 0 : slog(ERROR,"Invalid input parameter: db_file_path\n");
40 : 0 : provide(FAILURE);
41 : : }
42 : :
43 [ - + ]: 30 : if(global_interrupt_flag == true)
44 : : {
45 : 0 : slog(TRACE,"The program has been gracefully terminated. Store the current database version is not required\n");
46 : 0 : provide(status);
47 : : }
48 : :
49 [ - + ]: 30 : if(config->dry_run == true)
50 : : {
51 : 0 : slog(TRACE,"Dry Run mode is enabled. Store the current database version is not required\n");
52 : 0 : provide(status);
53 : : }
54 : :
55 : : /* Open database connection */
56 : 30 : rc = sqlite3_open_v2(db_file_path,&db,SQLITE_OPEN_READWRITE,NULL);
57 : :
58 [ - + ]: 30 : if(SQLITE_OK != rc)
59 : : {
60 : 0 : log_sqlite_error(db,rc,NULL,"Failed to open database");
61 : 0 : status = FAILURE;
62 : : }
63 : :
64 [ + - ]: 30 : if(SUCCESS == status)
65 : : {
66 : : /* Begin transaction */
67 : 30 : rc = sqlite3_exec(db,"BEGIN TRANSACTION",NULL,NULL,NULL);
68 : :
69 [ - + ]: 30 : if(SQLITE_OK != rc)
70 : : {
71 : 0 : log_sqlite_error(db,rc,NULL,"Failed to begin transaction");
72 : 0 : status = FAILURE;
73 : : }
74 : : }
75 : :
76 [ + - ]: 30 : if(SUCCESS == status)
77 : : {
78 : : /* Remove all from the table */
79 : 30 : rc = sqlite3_exec(db,"DELETE FROM metadata;",NULL,NULL,NULL);
80 : :
81 [ - + ]: 30 : if(SQLITE_OK != rc)
82 : : {
83 : 0 : log_sqlite_error(db,rc,NULL,"Failed to remove all from the table");
84 : 0 : status = FAILURE;
85 : : }
86 : : }
87 : :
88 : : /* Insert version number */
89 [ + - ]: 30 : if(SUCCESS == status)
90 : : {
91 : 30 : rc = sqlite3_prepare_v2(db,"INSERT INTO metadata (db_version) VALUES(?);",-1,&stmt,NULL);
92 : :
93 [ - + ]: 30 : if(SQLITE_OK != rc)
94 : : {
95 : 0 : log_sqlite_error(db,rc,NULL,"Failed to prepare insert query");
96 : 0 : status = FAILURE;
97 : : } else {
98 : 30 : slog(TRACE,"The database version %d has been successfully stored in the DB\n",version);
99 : : }
100 : : }
101 : :
102 [ + - ]: 30 : if(SUCCESS == status)
103 : : {
104 : 30 : rc = sqlite3_bind_int(stmt,1,version);
105 : :
106 [ - + ]: 30 : if(SQLITE_OK != rc)
107 : : {
108 : 0 : log_sqlite_error(db,rc,NULL,"Failed to bind version number");
109 : 0 : status = FAILURE;
110 : : }
111 : : }
112 : :
113 [ + - ]: 30 : if(SUCCESS == status)
114 : : {
115 : 30 : rc = sqlite3_step(stmt);
116 : :
117 [ - + ]: 30 : if(SQLITE_DONE != rc)
118 : : {
119 : 0 : log_sqlite_error(db,rc,NULL,"Failed to execute insert query");
120 : 0 : status = FAILURE;
121 : : }
122 : : }
123 : :
124 [ + - ]: 30 : if(SUCCESS == status)
125 : : {
126 : : /* Commit transaction */
127 : 30 : rc = sqlite3_exec(db,"COMMIT",NULL,NULL,NULL);
128 : :
129 [ - + ]: 30 : if(SQLITE_OK != rc)
130 : : {
131 : 0 : log_sqlite_error(db,rc,NULL,"Failed to commit transaction");
132 : 0 : status = FAILURE;
133 : : } else {
134 : 30 : db_file_modified = true;
135 : :
136 [ + + ]: 30 : if(strcmp(db_file_path,confstr(db_primary_file_path)) == 0)
137 : : {
138 : : /* Changes have been made to the database. Update
139 : : this in the global variable value. */
140 : 14 : config->db_primary_file_modified = true;
141 : : }
142 : : }
143 : : }
144 : :
145 [ - + ]: 30 : if(SUCCESS != status)
146 : : {
147 : : /* Attempt rollback */
148 : 0 : rc = sqlite3_exec(db,"ROLLBACK",NULL,NULL,NULL);
149 : :
150 [ # # ]: 0 : if(SQLITE_OK == rc)
151 : : {
152 : 0 : slog(TRACE,"The transaction has been rolled back\n");
153 : : } else {
154 : 0 : log_sqlite_error(db,rc,NULL,"Failed to rollback transaction");
155 : : }
156 : : }
157 : :
158 : : /* Cleanup */
159 : 30 : sqlite3_finalize(stmt);
160 : :
161 : : /* Cleanup */
162 : 30 : call(db_close(db,&db_file_modified));
163 : :
164 : 30 : provide(status);
165 : : }
|