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