Update my copyright and lgpl to 2.1
[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 = {0, NULL};
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 lms_db_table_updater_t _db_table_updater_images[] = {
92     _db_table_updater_images_0
93 };
94
95
96 static int
97 _db_create_table_if_required(sqlite3 *db)
98 {
99     return lms_db_table_update_if_required(db, "images",
100          LMS_ARRAY_SIZE(_db_table_updater_images),
101          _db_table_updater_images);
102 }
103
104 /**
105  * Create image DB access tool.
106  *
107  * Creates or get a reference to tools to access 'images' table in an
108  * optimized and easy way.
109  *
110  * This is usually called from plugin's @b setup() callback with the @p db
111  * got from @c ctxt.
112  *
113  * @param db database connection.
114  *
115  * @return DB access tool handle.
116  * @ingroup LMS_Plugins
117  */
118 lms_db_image_t *
119 lms_db_image_new(sqlite3 *db)
120 {
121     lms_db_image_t *ldi;
122     void *p;
123
124     if (lms_db_cache_get(&_cache, db, &p) == 0) {
125         ldi = p;
126         ldi->_references++;
127         return ldi;
128     }
129
130     if (!db)
131         return NULL;
132
133     if (_db_create_table_if_required(db) != 0) {
134         fprintf(stderr, "ERROR: could not create table.\n");
135         return NULL;
136     }
137
138     ldi = calloc(1, sizeof(lms_db_image_t));
139     ldi->_references = 1;
140     ldi->db = db;
141
142     if (lms_db_cache_add(&_cache, db, ldi) != 0) {
143         lms_db_image_free(ldi);
144         return NULL;
145     }
146
147     return ldi;
148 }
149
150 /**
151  * Start image DB access tool.
152  *
153  * Compile SQL statements and other initialization functions.
154  *
155  * This is usually called from plugin's @b start() callback.
156  *
157  * @param ldi handle returned by lms_db_image_new().
158  *
159  * @return On success 0 is returned.
160  * @ingroup LMS_Plugins
161  */
162 int
163 lms_db_image_start(lms_db_image_t *ldi)
164 {
165     if (!ldi)
166         return -1;
167     if (ldi->_is_started)
168         return 0;
169
170     ldi->insert = lms_db_compile_stmt(ldi->db,
171         "INSERT OR REPLACE INTO images ("
172         "id, title, artist, date, width, height, orientation, "
173         "gps_lat, gps_long, gps_alt) VALUES ("
174         "?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
175     if (!ldi->insert)
176         return -2;
177
178     ldi->_is_started = 1;
179     return 0;
180 }
181
182 /**
183  * Free image DB access tool.
184  *
185  * Unreference and possible free resources allocated to access tool.
186  *
187  * This is usually called from plugin's @b finish() callback.
188  *
189  * @param ldi handle returned by lms_db_image_new().
190  *
191  * @return On success 0 is returned.
192  * @ingroup LMS_Plugins
193  */
194 int
195 lms_db_image_free(lms_db_image_t *ldi)
196 {
197     int r;
198
199     if (!ldi)
200         return -1;
201     if (ldi->_references == 0) {
202         fprintf(stderr, "ERROR: over-called lms_db_image_free(%p)\n", ldi);
203         return -1;
204     }
205
206     ldi->_references--;
207     if (ldi->_references > 0)
208         return 0;
209
210     if (ldi->insert)
211         lms_db_finalize_stmt(ldi->insert, "insert");
212
213     r = lms_db_cache_del(&_cache, ldi->db, ldi);
214     free(ldi);
215
216     return r;
217 }
218
219 static int
220 _db_insert(lms_db_image_t *ldi, const struct lms_image_info *info)
221 {
222     sqlite3_stmt *stmt;
223     int r, ret;
224
225     stmt = ldi->insert;
226
227     ret = lms_db_bind_int64(stmt, 1, info->id);
228     if (ret != 0)
229         goto done;
230
231     ret = lms_db_bind_text(stmt, 2, info->title.str, info->title.len);
232     if (ret != 0)
233         goto done;
234
235     ret = lms_db_bind_text(stmt, 3, info->artist.str, info->artist.len);
236     if (ret != 0)
237         goto done;
238
239     ret = lms_db_bind_int(stmt, 4, info->date);
240     if (ret != 0)
241         goto done;
242
243     ret = lms_db_bind_int(stmt, 5, info->width);
244     if (ret != 0)
245         goto done;
246
247     ret = lms_db_bind_int(stmt, 6, info->height);
248     if (ret != 0)
249         goto done;
250
251     ret = lms_db_bind_int(stmt, 7, info->orientation);
252     if (ret != 0)
253         goto done;
254
255     ret = lms_db_bind_double(stmt, 8, info->gps.latitude);
256     if (ret != 0)
257         goto done;
258
259     ret = lms_db_bind_double(stmt, 9, info->gps.longitude);
260     if (ret != 0)
261         goto done;
262
263     ret = lms_db_bind_double(stmt, 10, info->gps.altitude);
264     if (ret != 0)
265         goto done;
266
267     r = sqlite3_step(stmt);
268     if (r != SQLITE_DONE) {
269         fprintf(stderr, "ERROR: could not insert image info: %s\n",
270                 sqlite3_errmsg(ldi->db));
271         ret = -11;
272         goto done;
273     }
274
275     ret = 0;
276
277   done:
278     lms_db_reset_stmt(stmt);
279
280     return ret;
281 }
282
283 /**
284  * Add image file to DB.
285  *
286  * This is usually called from plugin's @b parse() callback.
287  *
288  * @param ldi handle returned by lms_db_image_new().
289  * @param info image information to store.
290  *
291  * @return On success 0 is returned.
292  * @ingroup LMS_Plugins
293  */
294 int
295 lms_db_image_add(lms_db_image_t *ldi, struct lms_image_info *info)
296 {
297     if (!ldi)
298         return -1;
299     if (!info)
300         return -2;
301     if (info->id < 1)
302         return -3;
303
304     return _db_insert(ldi, info);
305 }