Add functions missing in older SQLite3 versions (maemo bora uses it).
[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, 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                      "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     ret = lms_db_create_trigger_if_not_exists(db,
56         "   delete_images_on_files_deleted "
57         "DELETE ON files FOR EACH ROW BEGIN "
58         "   DELETE FROM images WHERE id = OLD.id; END;");
59     if (ret != 0)
60         goto done;
61
62     ret = lms_db_create_trigger_if_not_exists(db,
63         "   delete_files_on_images_deleted "
64         "DELETE ON images FOR EACH ROW BEGIN "
65         "   DELETE FROM files WHERE id = OLD.id; END;");
66
67   done:
68     return ret;
69 }
70
71 static int
72 _db_compile_all_stmts(lms_db_image_t *ldi)
73 {
74     ldi->insert = lms_db_compile_stmt(ldi->db,
75         "INSERT OR REPLACE INTO images ("
76         "id, title, artist, date, width, height, orientation, "
77         "thumb_width, thumb_height, gps_lat, gps_long, gps_alt) VALUES ("
78         "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
79     if (!ldi->insert)
80         return -1;
81
82     return 0;
83 }
84
85 lms_db_image_t *
86 lms_db_image_new(sqlite3 *db)
87 {
88     lms_db_image_t *ldi;
89
90     if (_singleton) {
91         _singleton->_references++;
92         return _singleton;
93     }
94
95     if (!db)
96         return NULL;
97
98     if (_db_create_table_if_required(db) != 0) {
99         fprintf(stderr, "ERROR: could not create table.\n");
100         return NULL;
101     }
102
103     ldi = calloc(1, sizeof(lms_db_image_t));
104     ldi->_references = 1;
105     ldi->db = db;
106
107     if (_db_compile_all_stmts(ldi) != 0) {
108         fprintf(stderr, "ERROR: could not compile image statements.\n");
109         lms_db_image_free(ldi);
110         return NULL;
111     }
112
113     return ldi;
114 }
115
116 int
117 lms_db_image_free(lms_db_image_t *ldi)
118 {
119     if (!ldi)
120         return -1;
121
122     ldi->_references--;
123     if (ldi->_references > 0)
124         return 0;
125
126     if (ldi->insert)
127         lms_db_finalize_stmt(ldi->insert, "insert");
128
129     free(ldi);
130     _singleton = NULL;
131
132     return 0;
133 }
134
135 int
136 _db_insert(lms_db_image_t *ldi, const struct lms_image_info *info)
137 {
138     sqlite3_stmt *stmt;
139     int r, ret;
140     unsigned long tw, th;
141
142     if (info->height < info->width) {
143         tw = 128;
144         th = (info->height * 128) / info->width;
145         if (th == 0)
146             th = 1;
147     } else if (info->height == info->width)
148         tw = th = 128;
149     else {
150         th = 128;
151         tw = (info->width * 128) / info->height;
152         if (tw == 0)
153             tw = 1;
154     }
155
156     stmt = ldi->insert;
157
158     ret = lms_db_bind_int64(stmt, 1, info->id);
159     if (ret != 0)
160         goto done;
161
162     ret = lms_db_bind_text(stmt, 2, info->title.str, info->title.len);
163     if (ret != 0)
164         goto done;
165
166     ret = lms_db_bind_text(stmt, 3, info->artist.str, info->artist.len);
167     if (ret != 0)
168         goto done;
169
170     ret = lms_db_bind_int(stmt, 4, info->date);
171     if (ret != 0)
172         goto done;
173
174     ret = lms_db_bind_int(stmt, 5, info->width);
175     if (ret != 0)
176         goto done;
177
178     ret = lms_db_bind_int(stmt, 6, info->height);
179     if (ret != 0)
180         goto done;
181
182     ret = lms_db_bind_int(stmt, 7, info->orientation);
183     if (ret != 0)
184         goto done;
185
186     ret = lms_db_bind_int(stmt, 8, tw);
187     if (ret != 0)
188         goto done;
189
190     ret = lms_db_bind_int(stmt, 9, th);
191     if (ret != 0)
192         goto done;
193
194     ret = lms_db_bind_double(stmt, 10, info->gps.latitude);
195     if (ret != 0)
196         goto done;
197
198     ret = lms_db_bind_double(stmt, 11, info->gps.longitude);
199     if (ret != 0)
200         goto done;
201
202     ret = lms_db_bind_double(stmt, 12, info->gps.altitude);
203     if (ret != 0)
204         goto done;
205
206     r = sqlite3_step(stmt);
207     if (r != SQLITE_DONE) {
208         fprintf(stderr, "ERROR: could not insert image info: %s\n",
209                 sqlite3_errmsg(ldi->db));
210         ret = -13;
211         goto done;
212     }
213
214     ret = 0;
215
216   done:
217     lms_db_reset_stmt(stmt);
218
219     return ret;
220 }
221
222 int
223 lms_db_image_add(lms_db_image_t *ldi, struct lms_image_info *info)
224 {
225     if (!ldi)
226         return -1;
227     if (!info)
228         return -2;
229     if (info->id < 1)
230         return -3;
231
232     return _db_insert(ldi, info);
233 }