Mercurial > molko
comparison libmlk-core/core/save.c @ 243:71b3b7036de7
misc: lot of cleanups,
- prefix libraries with libmlk,
- move assets from source directories closes #2520,
- prefix header guards closes #2519
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sat, 28 Nov 2020 22:37:30 +0100 |
parents | libcore/core/save.c@76afe639fd72 |
children | f978fa0137ce |
comparison
equal
deleted
inserted
replaced
242:4c24604efcab | 243:71b3b7036de7 |
---|---|
1 /* | |
2 * save.c -- save functions | |
3 * | |
4 * Copyright (c) 2020 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #include <assert.h> | |
20 #include <stdio.h> | |
21 #include <stdlib.h> | |
22 #include <string.h> | |
23 | |
24 #include <sqlite3.h> | |
25 | |
26 #include <assets/sql/init.h> | |
27 #include <assets/sql/property-get.h> | |
28 #include <assets/sql/property-remove.h> | |
29 #include <assets/sql/property-set.h> | |
30 | |
31 #include "core_p.h" | |
32 #include "error.h" | |
33 #include "save.h" | |
34 #include "sys.h" | |
35 #include "util.h" | |
36 | |
37 #define SQL_BEGIN "BEGIN EXCLUSIVE TRANSACTION" | |
38 #define SQL_COMMIT "COMMIT" | |
39 #define SQL_ROLLBACK "ROLLBACK" | |
40 | |
41 static bool | |
42 exec(struct save *db, const char *sql) | |
43 { | |
44 if (sqlite3_exec(db->handle, sql, NULL, NULL, NULL) != SQLITE_OK) | |
45 return errorf("%s", sqlite3_errmsg(db->handle)); | |
46 | |
47 return true; | |
48 } | |
49 | |
50 static const char * | |
51 path(unsigned int idx) | |
52 { | |
53 return pprintf("%s/%u", sys_dir(SYS_DIR_SAVE), idx); | |
54 } | |
55 | |
56 static bool | |
57 execu(struct save *db, const unsigned char *sql) | |
58 { | |
59 return exec(db, (const char *)sql); | |
60 } | |
61 | |
62 bool | |
63 save_open(struct save *db, unsigned int idx, enum save_mode mode) | |
64 { | |
65 assert(db); | |
66 | |
67 return save_open_path(db, path(idx), mode); | |
68 } | |
69 | |
70 bool | |
71 verify(struct save *db) | |
72 { | |
73 struct { | |
74 time_t *date; | |
75 struct save_property prop; | |
76 } table[] = { | |
77 { .date = &db->created, { .key = "molko.create-date" } }, | |
78 { .date = &db->updated, { .key = "molko.update-date" } }, | |
79 }; | |
80 | |
81 /* Ensure create and update dates are present. */ | |
82 for (size_t i = 0; i < NELEM(table); ++i) { | |
83 if (!save_get_property(db, &table[i].prop)) { | |
84 sqlite3_close(db->handle); | |
85 return errorf(_("database not initialized correctly")); | |
86 } | |
87 | |
88 *table[i].date = strtoull(table[i].prop.value, NULL, 10); | |
89 } | |
90 | |
91 return true; | |
92 } | |
93 | |
94 bool | |
95 save_open_path(struct save *db, const char *path, enum save_mode mode) | |
96 { | |
97 assert(db); | |
98 assert(path); | |
99 | |
100 int flags = 0; | |
101 | |
102 switch (mode) { | |
103 case SAVE_MODE_WRITE: | |
104 flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; | |
105 break; | |
106 default: | |
107 flags = SQLITE_OPEN_READONLY; | |
108 break; | |
109 } | |
110 | |
111 if (sqlite3_open_v2(path, (sqlite3**)&db->handle, flags, NULL) != SQLITE_OK) | |
112 return errorf("%s", sqlite3_errmsg(db->handle)); | |
113 | |
114 if (mode == SAVE_MODE_WRITE) { | |
115 if (!execu(db, sql_init)) { | |
116 sqlite3_close(db->handle); | |
117 return false; | |
118 } | |
119 } | |
120 | |
121 return verify(db); | |
122 } | |
123 | |
124 bool | |
125 save_set_property(struct save *db, const struct save_property *prop) | |
126 { | |
127 assert(db); | |
128 assert(prop); | |
129 | |
130 sqlite3_stmt *stmt = NULL; | |
131 | |
132 if (!exec(db, SQL_BEGIN)) | |
133 return false; | |
134 if (sqlite3_prepare(db->handle, (const char *)sql_property_set, -1, &stmt, NULL) != SQLITE_OK) | |
135 goto sqlite3_err; | |
136 if (sqlite3_bind_text(stmt, 1, prop->key, -1, NULL) != SQLITE_OK || | |
137 sqlite3_bind_text(stmt, 2, prop->value, -1, NULL) != SQLITE_OK) | |
138 goto sqlite3_err; | |
139 if (sqlite3_step(stmt) != SQLITE_DONE) | |
140 goto sqlite3_err; | |
141 | |
142 sqlite3_finalize(stmt); | |
143 | |
144 return exec(db, SQL_COMMIT); | |
145 | |
146 sqlite3_err: | |
147 errorf("%s", sqlite3_errmsg(db->handle)); | |
148 | |
149 if (stmt) | |
150 sqlite3_finalize(stmt); | |
151 | |
152 exec(db, SQL_ROLLBACK); | |
153 | |
154 return false; | |
155 } | |
156 | |
157 bool | |
158 save_get_property(struct save *db, struct save_property *prop) | |
159 { | |
160 assert(db); | |
161 assert(prop); | |
162 | |
163 sqlite3_stmt *stmt = NULL; | |
164 bool ret = true; | |
165 | |
166 if (sqlite3_prepare(db->handle, (const char *)sql_property_get, | |
167 sizeof (sql_property_get), &stmt, NULL) != SQLITE_OK) | |
168 goto sqlite3_err; | |
169 if (sqlite3_bind_text(stmt, 1, prop->key, -1, NULL) != SQLITE_OK) | |
170 goto sqlite3_err; | |
171 | |
172 switch (sqlite3_step(stmt)) { | |
173 case SQLITE_DONE: | |
174 /* Not found. */ | |
175 ret = errorf(_("property '%s' was not found"), prop->key); | |
176 break; | |
177 case SQLITE_ROW: | |
178 /* Found. */ | |
179 snprintf(prop->value, sizeof (prop->value), "%s", sqlite3_column_text(stmt, 0)); | |
180 break; | |
181 default: | |
182 /* Error. */ | |
183 goto sqlite3_err; | |
184 } | |
185 | |
186 sqlite3_finalize(stmt); | |
187 | |
188 return ret; | |
189 | |
190 sqlite3_err: | |
191 errorf("%s", sqlite3_errmsg(db->handle)); | |
192 | |
193 if (stmt) | |
194 sqlite3_finalize(stmt); | |
195 | |
196 return false; | |
197 } | |
198 | |
199 bool | |
200 save_remove_property(struct save *db, const struct save_property *prop) | |
201 { | |
202 assert(db); | |
203 assert(prop); | |
204 | |
205 sqlite3_stmt *stmt = NULL; | |
206 | |
207 if (!exec(db, SQL_BEGIN)) | |
208 return false; | |
209 if (sqlite3_prepare(db->handle, (const char *)sql_property_remove, | |
210 sizeof (sql_property_remove), &stmt, NULL) != SQLITE_OK) | |
211 goto sqlite3_err; | |
212 if (sqlite3_bind_text(stmt, 1, prop->key, -1, NULL) != SQLITE_OK) | |
213 goto sqlite3_err; | |
214 if (sqlite3_step(stmt) != SQLITE_DONE) | |
215 goto sqlite3_err; | |
216 | |
217 sqlite3_finalize(stmt); | |
218 | |
219 return exec(db, SQL_COMMIT); | |
220 | |
221 sqlite3_err: | |
222 errorf("%s", sqlite3_errmsg(db->handle)); | |
223 | |
224 if (stmt) | |
225 sqlite3_finalize(stmt); | |
226 | |
227 exec(db, SQL_ROLLBACK); | |
228 | |
229 return false; | |
230 } | |
231 | |
232 void | |
233 save_finish(struct save *db) | |
234 { | |
235 assert(db); | |
236 | |
237 if (db->handle) | |
238 sqlite3_close(db->handle); | |
239 | |
240 memset(db, 0, sizeof (*db)); | |
241 } |