add dlna fields to image table.
[platform/upstream/lightmediascanner.git] / src / lib / lightmediascanner_db_image.c
1 /**
2  * Copyright (C) 2008-2011 by ProFUSION embedded systems
3  * Copyright (C) 2007 by INdT
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License
7  * as published by the Free Software Foundation; either version 2.1 of
8  * the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA
19  *
20  * @author Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
21  */
22
23 #include <lightmediascanner_db.h>
24 #include "lightmediascanner_db_private.h"
25 #include <stdlib.h>
26 #include <stdio.h>
27
28 struct lms_db_image {
29     sqlite3 *db;
30     sqlite3_stmt *insert;
31     unsigned int _references;
32     unsigned int _is_started:1;
33 };
34
35 static struct lms_db_cache _cache = { };
36
37 static int
38 _db_table_updater_images_0(sqlite3 *db, const char *table, unsigned int current_version, int is_last_run) {
39     char *errmsg;
40     int r, ret;
41
42     errmsg = NULL;
43     r = sqlite3_exec(db,
44                      "CREATE TABLE IF NOT EXISTS images ("
45                      "id INTEGER PRIMARY KEY, "
46                      "title TEXT, "
47                      "artist TEXT, "
48                      "date INTEGER NOT NULL, "
49                      "width INTEGER NOT NULL, "
50                      "height INTEGER NOT NULL, "
51                      "orientation INTEGER NOT NULL, "
52                      "gps_lat REAL DEFAULT 0.0, "
53                      "gps_long REAL DEFAULT 0.0, "
54                      "gps_alt REAL DEFAULT 0.0"
55                      ")",
56                      NULL, NULL, &errmsg);
57     if (r != SQLITE_OK) {
58         fprintf(stderr, "ERROR: could not create 'images' table: %s\n", errmsg);
59         sqlite3_free(errmsg);
60         return -1;
61     }
62
63     r = sqlite3_exec(db,
64                      "CREATE INDEX IF NOT EXISTS images_date_idx ON images ("
65                      "date"
66                      ")",
67                      NULL, NULL, &errmsg);
68     if (r != SQLITE_OK) {
69         fprintf(stderr, "ERROR: could not create 'images_date_idx' index: %s\n",
70                 errmsg);
71         sqlite3_free(errmsg);
72         return -2;
73     }
74
75     ret = lms_db_create_trigger_if_not_exists(db,
76         "delete_images_on_files_deleted "
77         "DELETE ON files FOR EACH ROW BEGIN "
78         " DELETE FROM images WHERE id = OLD.id; END;");
79     if (ret != 0)
80         goto done;
81
82     ret = lms_db_create_trigger_if_not_exists(db,
83         "delete_files_on_images_deleted "
84         "DELETE ON images FOR EACH ROW BEGIN "
85         " DELETE FROM files WHERE id = OLD.id; END;");
86
87   done:
88     return ret;
89 }
90
91 static int
92 _db_table_updater_images_1(sqlite3 *db, const char *table, unsigned int current_version, int is_last_run)
93 {
94     int ret;
95     char *err;
96
97     ret = sqlite3_exec(
98         db, "BEGIN TRANSACTION;"
99         "ALTER TABLE images ADD COLUMN dlna_profile TEXT DEFAULT NULL;"
100         "ALTER TABLE images ADD COLUMN dlna_mime TEXT DEFAULT NULL;"
101         "COMMIT;",
102         NULL, NULL, &err);
103     if (ret != SQLITE_OK) {
104         fprintf(stderr, "ERROR: could add columns to images table: %s\n", err);
105         sqlite3_free(err);
106     }
107
108     return ret;
109 }
110
111 static lms_db_table_updater_t _db_table_updater_images[] = {
112     _db_table_updater_images_0,
113     _db_table_updater_images_1
114 };
115
116
117 static int
118 _db_create_table_if_required(sqlite3 *db)
119 {
120     return lms_db_table_update_if_required(db, "images",
121          LMS_ARRAY_SIZE(_db_table_updater_images),
122          _db_table_updater_images);
123 }
124
125 /**
126  * Create image DB access tool.
127  *
128  * Creates or get a reference to tools to access 'images' table in an
129  * optimized and easy way.
130  *
131  * This is usually called from plugin's @b setup() callback with the @p db
132  * got from @c ctxt.
133  *
134  * @param db database connection.
135  *
136  * @return DB access tool handle.
137  * @ingroup LMS_Plugins
138  */
139 lms_db_image_t *
140 lms_db_image_new(sqlite3 *db)
141 {
142     lms_db_image_t *ldi;
143     void *p;
144
145     if (lms_db_cache_get(&_cache, db, &p) == 0) {
146         ldi = p;
147         ldi->_references++;
148         return ldi;
149     }
150
151     if (!db)
152         return NULL;
153
154     if (_db_create_table_if_required(db) != 0) {
155         fprintf(stderr, "ERROR: could not create table.\n");
156         return NULL;
157     }
158
159     ldi = calloc(1, sizeof(lms_db_image_t));
160     ldi->_references = 1;
161     ldi->db = db;
162
163     if (lms_db_cache_add(&_cache, db, ldi) != 0) {
164         lms_db_image_free(ldi);
165         return NULL;
166     }
167
168     return ldi;
169 }
170
171 /**
172  * Start image DB access tool.
173  *
174  * Compile SQL statements and other initialization functions.
175  *
176  * This is usually called from plugin's @b start() callback.
177  *
178  * @param ldi handle returned by lms_db_image_new().
179  *
180  * @return On success 0 is returned.
181  * @ingroup LMS_Plugins
182  */
183 int
184 lms_db_image_start(lms_db_image_t *ldi)
185 {
186     if (!ldi)
187         return -1;
188     if (ldi->_is_started)
189         return 0;
190
191     ldi->insert = lms_db_compile_stmt(ldi->db,
192         "INSERT OR REPLACE INTO images ("
193         "id, title, artist, date, width, height, orientation, "
194         "gps_lat, gps_long, gps_alt, dlna_profile, dlna_mime) VALUES ("
195         "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
196     if (!ldi->insert)
197         return -2;
198
199     ldi->_is_started = 1;
200     return 0;
201 }
202
203 /**
204  * Free image DB access tool.
205  *
206  * Unreference and possible free resources allocated to access tool.
207  *
208  * This is usually called from plugin's @b finish() callback.
209  *
210  * @param ldi handle returned by lms_db_image_new().
211  *
212  * @return On success 0 is returned.
213  * @ingroup LMS_Plugins
214  */
215 int
216 lms_db_image_free(lms_db_image_t *ldi)
217 {
218     int r;
219
220     if (!ldi)
221         return -1;
222     if (ldi->_references == 0) {
223         fprintf(stderr, "ERROR: over-called lms_db_image_free(%p)\n", ldi);
224         return -1;
225     }
226
227     ldi->_references--;
228     if (ldi->_references > 0)
229         return 0;
230
231     if (ldi->insert)
232         lms_db_finalize_stmt(ldi->insert, "insert");
233
234     r = lms_db_cache_del(&_cache, ldi->db, ldi);
235     free(ldi);
236
237     return r;
238 }
239
240 static int
241 _db_insert(lms_db_image_t *ldi, const struct lms_image_info *info)
242 {
243     sqlite3_stmt *stmt;
244     int r, ret;
245
246     stmt = ldi->insert;
247
248     ret = lms_db_bind_int64(stmt, 1, info->id);
249     if (ret != 0)
250         goto done;
251
252     ret = lms_db_bind_text(stmt, 2, info->title.str, info->title.len);
253     if (ret != 0)
254         goto done;
255
256     ret = lms_db_bind_text(stmt, 3, info->artist.str, info->artist.len);
257     if (ret != 0)
258         goto done;
259
260     ret = lms_db_bind_int(stmt, 4, info->date);
261     if (ret != 0)
262         goto done;
263
264     ret = lms_db_bind_int(stmt, 5, info->width);
265     if (ret != 0)
266         goto done;
267
268     ret = lms_db_bind_int(stmt, 6, info->height);
269     if (ret != 0)
270         goto done;
271
272     ret = lms_db_bind_int(stmt, 7, info->orientation);
273     if (ret != 0)
274         goto done;
275
276     ret = lms_db_bind_double(stmt, 8, info->gps.latitude);
277     if (ret != 0)
278         goto done;
279
280     ret = lms_db_bind_double(stmt, 9, info->gps.longitude);
281     if (ret != 0)
282         goto done;
283
284     ret = lms_db_bind_double(stmt, 10, info->gps.altitude);
285     if (ret != 0)
286         goto done;
287
288     ret = lms_db_bind_text(stmt, 11, info->dlna_profile.str,
289                            info->dlna_profile.len);
290     if (ret != 0)
291         goto done;
292
293     ret = lms_db_bind_text(stmt, 12, info->dlna_mime.str, info->dlna_mime.len);
294     if (ret != 0)
295         goto done;
296
297     r = sqlite3_step(stmt);
298     if (r != SQLITE_DONE) {
299         fprintf(stderr, "ERROR: could not insert image info: %s\n",
300                 sqlite3_errmsg(ldi->db));
301         ret = -11;
302         goto done;
303     }
304
305     ret = 0;
306
307   done:
308     lms_db_reset_stmt(stmt);
309
310     return ret;
311 }
312
313 /**
314  * Add image file to DB.
315  *
316  * This is usually called from plugin's @b parse() callback.
317  *
318  * @param ldi handle returned by lms_db_image_new().
319  * @param info image information to store.
320  *
321  * @return On success 0 is returned.
322  * @ingroup LMS_Plugins
323  */
324 int
325 lms_db_image_add(lms_db_image_t *ldi, struct lms_image_info *info)
326 {
327     if (!ldi)
328         return -1;
329     if (!info)
330         return -2;
331     if (info->id < 1)
332         return -3;
333
334     return _db_insert(ldi, info);
335 }