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