Cache lms_db_* per DB instance instead of globally.
[platform/upstream/lightmediascanner.git] / src / lib / lightmediascanner_db_image.c
1 #include <lightmediascanner_db.h>
2 #include "lightmediascanner_db_private.h"
3 #include <stdlib.h>
4 #include <stdio.h>
5
6 struct lms_db_image {
7     sqlite3 *db;
8     sqlite3_stmt *insert;
9     unsigned int _references;
10     unsigned int _is_started:1;
11 };
12
13 static struct lms_db_cache _cache = {0, NULL};
14
15 static int
16 _db_table_updater_images_0(sqlite3 *db, const char *table, unsigned int current_version, int is_last_run) {
17     char *errmsg;
18     int r, ret;
19
20     errmsg = NULL;
21     r = sqlite3_exec(db,
22                      "CREATE TABLE IF NOT EXISTS images ("
23                      "id INTEGER PRIMARY KEY, "
24                      "title TEXT, "
25                      "artist TEXT, "
26                      "date INTEGER NOT NULL, "
27                      "width INTEGER NOT NULL, "
28                      "height INTEGER NOT NULL, "
29                      "orientation INTEGER NOT NULL, "
30                      "gps_lat REAL DEFAULT 0.0, "
31                      "gps_long REAL DEFAULT 0.0, "
32                      "gps_alt REAL DEFAULT 0.0"
33                      ")",
34                      NULL, NULL, &errmsg);
35     if (r != SQLITE_OK) {
36         fprintf(stderr, "ERROR: could not create 'images' table: %s\n", errmsg);
37         sqlite3_free(errmsg);
38         return -1;
39     }
40
41     r = sqlite3_exec(db,
42                      "CREATE INDEX IF NOT EXISTS images_date_idx ON images ("
43                      "date"
44                      ")",
45                      NULL, NULL, &errmsg);
46     if (r != SQLITE_OK) {
47         fprintf(stderr, "ERROR: could not create 'images_date_idx' index: %s\n",
48                 errmsg);
49         sqlite3_free(errmsg);
50         return -2;
51     }
52
53     ret = lms_db_create_trigger_if_not_exists(db,
54         "delete_images_on_files_deleted "
55         "DELETE ON files FOR EACH ROW BEGIN "
56         " DELETE FROM images WHERE id = OLD.id; END;");
57     if (ret != 0)
58         goto done;
59
60     ret = lms_db_create_trigger_if_not_exists(db,
61         "delete_files_on_images_deleted "
62         "DELETE ON images FOR EACH ROW BEGIN "
63         " DELETE FROM files WHERE id = OLD.id; END;");
64
65   done:
66     return ret;
67 }
68
69 static lms_db_table_updater_t _db_table_updater_images[] = {
70     _db_table_updater_images_0
71 };
72
73
74 static int
75 _db_create_table_if_required(sqlite3 *db)
76 {
77     return lms_db_table_update_if_required(db, "images",
78          LMS_ARRAY_SIZE(_db_table_updater_images),
79          _db_table_updater_images);
80 }
81
82 lms_db_image_t *
83 lms_db_image_new(sqlite3 *db)
84 {
85     lms_db_image_t *ldi;
86
87     if (lms_db_cache_get(&_cache, db, (void**)&ldi) == 0) {
88         ldi->_references++;
89         return ldi;
90     }
91
92     if (!db)
93         return NULL;
94
95     if (_db_create_table_if_required(db) != 0) {
96         fprintf(stderr, "ERROR: could not create table.\n");
97         return NULL;
98     }
99
100     ldi = calloc(1, sizeof(lms_db_image_t));
101     ldi->_references = 1;
102     ldi->db = db;
103
104     if (lms_db_cache_add(&_cache, db, ldi) != 0) {
105         lms_db_image_free(ldi);
106         return NULL;
107     }
108
109     return ldi;
110 }
111
112 int
113 lms_db_image_start(lms_db_image_t *ldi)
114 {
115     if (!ldi)
116         return -1;
117     if (ldi->_is_started)
118         return 0;
119
120     ldi->insert = lms_db_compile_stmt(ldi->db,
121         "INSERT OR REPLACE INTO images ("
122         "id, title, artist, date, width, height, orientation, "
123         "gps_lat, gps_long, gps_alt) VALUES ("
124         "?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
125     if (!ldi->insert)
126         return -2;
127
128     ldi->_is_started = 1;
129     return 0;
130 }
131
132 int
133 lms_db_image_free(lms_db_image_t *ldi)
134 {
135     int r;
136
137     if (!ldi)
138         return -1;
139     if (ldi->_references == 0) {
140         fprintf(stderr, "ERROR: over-called lms_db_image_free(%p)\n", ldi);
141         return -1;
142     }
143
144     ldi->_references--;
145     if (ldi->_references > 0)
146         return 0;
147
148     if (ldi->insert)
149         lms_db_finalize_stmt(ldi->insert, "insert");
150
151     r = lms_db_cache_del(&_cache, ldi->db, ldi);
152     free(ldi);
153
154     return r;
155 }
156
157 static int
158 _db_insert(lms_db_image_t *ldi, const struct lms_image_info *info)
159 {
160     sqlite3_stmt *stmt;
161     int r, ret;
162
163     stmt = ldi->insert;
164
165     ret = lms_db_bind_int64(stmt, 1, info->id);
166     if (ret != 0)
167         goto done;
168
169     ret = lms_db_bind_text(stmt, 2, info->title.str, info->title.len);
170     if (ret != 0)
171         goto done;
172
173     ret = lms_db_bind_text(stmt, 3, info->artist.str, info->artist.len);
174     if (ret != 0)
175         goto done;
176
177     ret = lms_db_bind_int(stmt, 4, info->date);
178     if (ret != 0)
179         goto done;
180
181     ret = lms_db_bind_int(stmt, 5, info->width);
182     if (ret != 0)
183         goto done;
184
185     ret = lms_db_bind_int(stmt, 6, info->height);
186     if (ret != 0)
187         goto done;
188
189     ret = lms_db_bind_int(stmt, 7, info->orientation);
190     if (ret != 0)
191         goto done;
192
193     ret = lms_db_bind_double(stmt, 8, info->gps.latitude);
194     if (ret != 0)
195         goto done;
196
197     ret = lms_db_bind_double(stmt, 9, info->gps.longitude);
198     if (ret != 0)
199         goto done;
200
201     ret = lms_db_bind_double(stmt, 10, info->gps.altitude);
202     if (ret != 0)
203         goto done;
204
205     r = sqlite3_step(stmt);
206     if (r != SQLITE_DONE) {
207         fprintf(stderr, "ERROR: could not insert image info: %s\n",
208                 sqlite3_errmsg(ldi->db));
209         ret = -11;
210         goto done;
211     }
212
213     ret = 0;
214
215   done:
216     lms_db_reset_stmt(stmt);
217
218     return ret;
219 }
220
221 int
222 lms_db_image_add(lms_db_image_t *ldi, struct lms_image_info *info)
223 {
224     if (!ldi)
225         return -1;
226     if (!info)
227         return -2;
228     if (info->id < 1)
229         return -3;
230
231     return _db_insert(ldi, info);
232 }