Split out db utilities from core and add image db functions.
[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     int _references;
10 };
11
12 lms_db_image_t *_singleton = NULL;
13
14 static int
15 _db_create_table_if_required(sqlite3 *db)
16 {
17     char *errmsg;
18     int r;
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                      "thumb_width INTEGER NOT NULL, "
31                      "thumb_height INTEGER NOT NULL, "
32                      "gps_lat REAL DEFAULT 0.0, "
33                      "gps_long REAL DEFAULT 0.0, "
34                      "gps_alt REAL DEFAULT 0.0"
35                      ")",
36                      NULL, NULL, &errmsg);
37     if (r != SQLITE_OK) {
38         fprintf(stderr, "ERROR: could not create 'images' table: %s\n", errmsg);
39         sqlite3_free(errmsg);
40         return -1;
41     }
42
43     r = sqlite3_exec(db,
44                      "CREATE INDEX IF NOT EXISTS images_date_idx ON images ("
45                      "date"
46                      ")",
47                      NULL, NULL, &errmsg);
48     if (r != SQLITE_OK) {
49         fprintf(stderr, "ERROR: could not create 'images_date_idx' index: %s\n",
50                 errmsg);
51         sqlite3_free(errmsg);
52         return -2;
53     }
54
55     r = sqlite3_exec(db,
56                      "CREATE TRIGGER IF NOT EXISTS"
57                      "   delete_images_on_files_deleted "
58                      "DELETE ON files "
59                      "FOR EACH ROW BEGIN "
60                      "   DELETE FROM images WHERE id = OLD.id;"
61                      "END;",
62                      NULL, NULL, &errmsg);
63     if (r != SQLITE_OK) {
64         fprintf(stderr, "ERROR: could not create trigger to delete images on "
65                 "files deletion: %s\n",
66                 errmsg);
67         sqlite3_free(errmsg);
68         return -2;
69     }
70
71     r = sqlite3_exec(db,
72                      "CREATE TRIGGER IF NOT EXISTS"
73                      "   delete_files_on_images_deleted "
74                      "DELETE ON images "
75                      "FOR EACH ROW BEGIN "
76                      "   DELETE FROM files WHERE id = OLD.id;"
77                      "END;",
78                      NULL, NULL, &errmsg);
79     if (r != SQLITE_OK) {
80         fprintf(stderr, "ERROR: could not create trigger to delete files on "
81                 "images deletion: %s\n",
82                 errmsg);
83         sqlite3_free(errmsg);
84         return -2;
85     }
86
87     return 0;
88 }
89
90 static int
91 _db_compile_all_stmts(lms_db_image_t *ldi)
92 {
93     ldi->insert = lms_db_compile_stmt(ldi->db,
94         "INSERT OR REPLACE INTO images ("
95         "id, title, artist, date, width, height, orientation, "
96         "thumb_width, thumb_height, gps_lat, gps_long, gps_alt) VALUES ("
97         "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
98     if (!ldi->insert)
99         return -1;
100
101     return 0;
102 }
103
104 lms_db_image_t *
105 lms_db_image_new(sqlite3 *db)
106 {
107     lms_db_image_t *ldi;
108
109     if (_singleton) {
110         _singleton->_references++;
111         return _singleton;
112     }
113
114     if (!db)
115         return NULL;
116
117     if (_db_create_table_if_required(db) != 0) {
118         fprintf(stderr, "ERROR: could not create table.\n");
119         return NULL;
120     }
121
122     ldi = calloc(1, sizeof(lms_db_image_t));
123     ldi->_references = 1;
124     ldi->db = db;
125
126     if (_db_compile_all_stmts(ldi) != 0) {
127         fprintf(stderr, "ERROR: could not compile image statements.\n");
128         lms_db_image_free(ldi);
129         return NULL;
130     }
131
132     return ldi;
133 }
134
135 int
136 lms_db_image_free(lms_db_image_t *ldi)
137 {
138     if (!ldi)
139         return -1;
140
141     ldi->_references--;
142     if (ldi->_references > 0)
143         return 0;
144
145     if (ldi->insert)
146         lms_db_finalize_stmt(ldi->insert, "insert");
147
148     free(ldi);
149     _singleton = NULL;
150
151     return 0;
152 }
153
154 int
155 _db_insert(lms_db_image_t *ldi, const struct lms_image_info *info)
156 {
157     sqlite3_stmt *stmt;
158     int r, ret;
159     unsigned long tw, th;
160
161     if (info->height < info->width) {
162         tw = 128;
163         th = (info->height * 128) / info->width;
164         if (th == 0)
165             th = 1;
166     } else if (info->height == info->width)
167         tw = th = 128;
168     else {
169         th = 128;
170         tw = (info->width * 128) / info->height;
171         if (tw == 0)
172             tw = 1;
173     }
174
175     stmt = ldi->insert;
176
177     ret = lms_db_bind_int64(stmt, 1, info->id);
178     if (ret != 0)
179         goto done;
180
181     ret = lms_db_bind_text(stmt, 2, info->title.str, info->title.len);
182     if (ret != 0)
183         goto done;
184
185     ret = lms_db_bind_text(stmt, 3, info->artist.str, info->artist.len);
186     if (ret != 0)
187         goto done;
188
189     ret = lms_db_bind_int(stmt, 4, info->date);
190     if (ret != 0)
191         goto done;
192
193     ret = lms_db_bind_int(stmt, 5, info->width);
194     if (ret != 0)
195         goto done;
196
197     ret = lms_db_bind_int(stmt, 6, info->height);
198     if (ret != 0)
199         goto done;
200
201     ret = lms_db_bind_int(stmt, 7, info->orientation);
202     if (ret != 0)
203         goto done;
204
205     ret = lms_db_bind_int(stmt, 8, tw);
206     if (ret != 0)
207         goto done;
208
209     ret = lms_db_bind_int(stmt, 9, th);
210     if (ret != 0)
211         goto done;
212
213     ret = lms_db_bind_double(stmt, 10, info->gps.latitude);
214     if (ret != 0)
215         goto done;
216
217     ret = lms_db_bind_double(stmt, 11, info->gps.longitude);
218     if (ret != 0)
219         goto done;
220
221     ret = lms_db_bind_double(stmt, 12, info->gps.altitude);
222     if (ret != 0)
223         goto done;
224
225     r = sqlite3_step(stmt);
226     if (r != SQLITE_DONE) {
227         fprintf(stderr, "ERROR: could not insert image info: %s\n",
228                 sqlite3_errmsg(ldi->db));
229         ret = -13;
230         goto done;
231     }
232
233     ret = 0;
234
235   done:
236     lms_db_reset_stmt(stmt);
237
238     return ret;
239 }
240
241 int
242 lms_db_image_add(lms_db_image_t *ldi, struct lms_image_info *info)
243 {
244     if (!ldi)
245         return -1;
246     if (!info)
247         return -2;
248     if (info->id < 1)
249         return -3;
250
251     return _db_insert(ldi, info);
252 }