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