Updated package version
[lms] / lightmediascanner / src / lib / lightmediascanner_db_playlist.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_playlist {
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_playlists_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 playlists ("
43                      "id INTEGER PRIMARY KEY, "
44                      "title TEXT, "
45                      "n_entries INTEGER NOT NULL"
46                      ")",
47                      NULL, NULL, &errmsg);
48     if (r != SQLITE_OK) {
49         fprintf(stderr, "ERROR: could not create 'playlists' table: %s\n",
50                 errmsg);
51         sqlite3_free(errmsg);
52         return -1;
53     }
54
55     r = sqlite3_exec(db,
56                      "CREATE INDEX IF NOT EXISTS playlists_title_idx ON "
57                      "playlists (title)",
58                      NULL, NULL, &errmsg);
59     if (r != SQLITE_OK) {
60         fprintf(stderr,
61                 "ERROR: could not create 'playlists_title_idx' index: %s\n",
62                 errmsg);
63         sqlite3_free(errmsg);
64         return -2;
65     }
66
67     ret = lms_db_create_trigger_if_not_exists(db,
68         "delete_playlists_on_files_deleted "
69         "DELETE ON files FOR EACH ROW BEGIN "
70         " DELETE FROM playlists WHERE id = OLD.id; END;");
71     if (ret != 0)
72         goto done;
73
74     ret = lms_db_create_trigger_if_not_exists(db,
75         "delete_files_on_playlists_deleted "
76         "DELETE ON playlists FOR EACH ROW BEGIN "
77         " DELETE FROM files WHERE id = OLD.id; END;");
78
79   done:
80     return ret;
81 }
82
83 static lms_db_table_updater_t _db_table_updater_playlists[] = {
84     _db_table_updater_playlists_0
85 };
86
87
88 static int
89 _db_create_table_if_required(sqlite3 *db)
90 {
91     return lms_db_table_update_if_required(db, "playlists",
92          LMS_ARRAY_SIZE(_db_table_updater_playlists),
93          _db_table_updater_playlists);
94 }
95
96 /**
97  * Create playlist DB access tool.
98  *
99  * Creates or get a reference to tools to access 'playlists' table in an
100  * optimized and easy way.
101  *
102  * This is usually called from plugin's @b setup() callback with the @p db
103  * got from @c ctxt.
104  *
105  * @param db database connection.
106  *
107  * @return DB access tool handle.
108  * @ingroup LMS_Plugins
109  */
110 lms_db_playlist_t *
111 lms_db_playlist_new(sqlite3 *db)
112 {
113     lms_db_playlist_t *ldp;
114     void *p;
115
116     if (lms_db_cache_get(&_cache, db, &p) == 0) {
117         ldp = p;
118         ldp->_references++;
119         return ldp;
120     }
121
122     if (!db)
123         return NULL;
124
125     if (_db_create_table_if_required(db) != 0) {
126         fprintf(stderr, "ERROR: could not create table.\n");
127         return NULL;
128     }
129
130     ldp = calloc(1, sizeof(lms_db_playlist_t));
131     ldp->_references = 1;
132     ldp->db = db;
133
134     if (lms_db_cache_add(&_cache, db, ldp) != 0) {
135         lms_db_playlist_free(ldp);
136         return NULL;
137     }
138
139     return ldp;
140 }
141
142 /**
143  * Start playlist DB access tool.
144  *
145  * Compile SQL statements and other initialization functions.
146  *
147  * This is usually called from plugin's @b start() callback.
148  *
149  * @param ldp handle returned by lms_db_playlist_new().
150  *
151  * @return On success 0 is returned.
152  * @ingroup LMS_Plugins
153  */
154 int
155 lms_db_playlist_start(lms_db_playlist_t *ldp)
156 {
157     if (!ldp)
158         return -1;
159     if (ldp->_is_started)
160         return 0;
161
162     ldp->insert = lms_db_compile_stmt(ldp->db,
163         "INSERT OR REPLACE INTO playlists (id, title, n_entries) "
164         "VALUES (?, ?, ?)");
165     if (!ldp->insert)
166         return -2;
167
168     ldp->_is_started = 1;
169     return 0;
170 }
171
172 /**
173  * Free playlist DB access tool.
174  *
175  * Unreference and possible free resources allocated to access tool.
176  *
177  * This is usually called from plugin's @b finish() callback.
178  *
179  * @param ldp handle returned by lms_db_playlist_new().
180  *
181  * @return On success 0 is returned.
182  * @ingroup LMS_Plugins
183  */
184 int
185 lms_db_playlist_free(lms_db_playlist_t *ldp)
186 {
187     int r;
188
189     if (!ldp)
190         return -1;
191     if (ldp->_references == 0) {
192         fprintf(stderr, "ERROR: over-called lms_db_playlist_free(%p)\n", ldp);
193         return -1;
194     }
195
196     ldp->_references--;
197     if (ldp->_references > 0)
198         return 0;
199
200     if (ldp->insert)
201         lms_db_finalize_stmt(ldp->insert, "insert");
202
203     r = lms_db_cache_del(&_cache, ldp->db, ldp);
204     free(ldp);
205
206     return r;
207 }
208
209 static int
210 _db_insert(lms_db_playlist_t *ldp, const struct lms_playlist_info *info)
211 {
212     sqlite3_stmt *stmt;
213     int r, ret;
214
215     stmt = ldp->insert;
216
217     ret = lms_db_bind_int64(stmt, 1, info->id);
218     if (ret != 0)
219         goto done;
220
221     ret = lms_db_bind_text(stmt, 2, info->title.str, info->title.len);
222     if (ret != 0)
223         goto done;
224
225     ret = lms_db_bind_int(stmt, 3, info->n_entries);
226     if (ret != 0)
227         goto done;
228
229     r = sqlite3_step(stmt);
230     if (r != SQLITE_DONE) {
231         fprintf(stderr, "ERROR: could not insert playlist info: %s\n",
232                 sqlite3_errmsg(ldp->db));
233         ret = -4;
234         goto done;
235     }
236
237     ret = 0;
238
239   done:
240     lms_db_reset_stmt(stmt);
241
242     return ret;
243 }
244
245 /**
246  * Add playlist file to DB.
247  *
248  * This is usually called from plugin's @b parse() callback.
249  *
250  * @param ldp handle returned by lms_db_playlist_new().
251  * @param info playlist information to store.
252  *
253  * @return On success 0 is returned.
254  * @ingroup LMS_Plugins
255  */
256 int
257 lms_db_playlist_add(lms_db_playlist_t *ldp, struct lms_playlist_info *info)
258 {
259     if (!ldp)
260         return -1;
261     if (!info)
262         return -2;
263     if (info->id < 1)
264         return -3;
265
266     return _db_insert(ldp, info);
267 }