Merge branch 'master' of /home/gustavo/Development/git/lightmediascanner
[lms] / lightmediascanner / src / lib / lightmediascanner_db_playlist.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_playlist {
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_playlists_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 playlists ("
23                      "id INTEGER PRIMARY KEY, "
24                      "title TEXT, "
25                      "n_entries INTEGER NOT NULL"
26                      ")",
27                      NULL, NULL, &errmsg);
28     if (r != SQLITE_OK) {
29         fprintf(stderr, "ERROR: could not create 'playlists' table: %s\n",
30                 errmsg);
31         sqlite3_free(errmsg);
32         return -1;
33     }
34
35     r = sqlite3_exec(db,
36                      "CREATE INDEX IF NOT EXISTS playlists_title_idx ON "
37                      "playlists (title)",
38                      NULL, NULL, &errmsg);
39     if (r != SQLITE_OK) {
40         fprintf(stderr,
41                 "ERROR: could not create 'playlists_title_idx' index: %s\n",
42                 errmsg);
43         sqlite3_free(errmsg);
44         return -2;
45     }
46
47     ret = lms_db_create_trigger_if_not_exists(db,
48         "delete_playlists_on_files_deleted "
49         "DELETE ON files FOR EACH ROW BEGIN "
50         " DELETE FROM playlists WHERE id = OLD.id; END;");
51     if (ret != 0)
52         goto done;
53
54     ret = lms_db_create_trigger_if_not_exists(db,
55         "delete_files_on_playlists_deleted "
56         "DELETE ON playlists FOR EACH ROW BEGIN "
57         " DELETE FROM files WHERE id = OLD.id; END;");
58
59   done:
60     return ret;
61 }
62
63 static lms_db_table_updater_t _db_table_updater_playlists[] = {
64     _db_table_updater_playlists_0
65 };
66
67
68 static int
69 _db_create_table_if_required(sqlite3 *db)
70 {
71     return lms_db_table_update_if_required(db, "playlists",
72          LMS_ARRAY_SIZE(_db_table_updater_playlists),
73          _db_table_updater_playlists);
74 }
75
76 lms_db_playlist_t *
77 lms_db_playlist_new(sqlite3 *db)
78 {
79     lms_db_playlist_t *ldp;
80     void *p;
81
82     if (lms_db_cache_get(&_cache, db, &p) == 0) {
83         ldp = p;
84         ldp->_references++;
85         return ldp;
86     }
87
88     if (!db)
89         return NULL;
90
91     if (_db_create_table_if_required(db) != 0) {
92         fprintf(stderr, "ERROR: could not create table.\n");
93         return NULL;
94     }
95
96     ldp = calloc(1, sizeof(lms_db_playlist_t));
97     ldp->_references = 1;
98     ldp->db = db;
99
100     if (lms_db_cache_add(&_cache, db, ldp) != 0) {
101         lms_db_playlist_free(ldp);
102         return NULL;
103     }
104
105     return ldp;
106 }
107
108 int
109 lms_db_playlist_start(lms_db_playlist_t *ldp)
110 {
111     if (!ldp)
112         return -1;
113     if (ldp->_is_started)
114         return 0;
115
116     ldp->insert = lms_db_compile_stmt(ldp->db,
117         "INSERT OR REPLACE INTO playlists (id, title, n_entries) "
118         "VALUES (?, ?, ?)");
119     if (!ldp->insert)
120         return -2;
121
122     ldp->_is_started = 1;
123     return 0;
124 }
125
126 int
127 lms_db_playlist_free(lms_db_playlist_t *ldp)
128 {
129     int r;
130
131     if (!ldp)
132         return -1;
133     if (ldp->_references == 0) {
134         fprintf(stderr, "ERROR: over-called lms_db_playlist_free(%p)\n", ldp);
135         return -1;
136     }
137
138     ldp->_references--;
139     if (ldp->_references > 0)
140         return 0;
141
142     if (ldp->insert)
143         lms_db_finalize_stmt(ldp->insert, "insert");
144
145     r = lms_db_cache_del(&_cache, ldp->db, ldp);
146     free(ldp);
147
148     return r;
149 }
150
151 static int
152 _db_insert(lms_db_playlist_t *ldp, const struct lms_playlist_info *info)
153 {
154     sqlite3_stmt *stmt;
155     int r, ret;
156
157     stmt = ldp->insert;
158
159     ret = lms_db_bind_int64(stmt, 1, info->id);
160     if (ret != 0)
161         goto done;
162
163     ret = lms_db_bind_text(stmt, 2, info->title.str, info->title.len);
164     if (ret != 0)
165         goto done;
166
167     ret = lms_db_bind_int(stmt, 3, info->n_entries);
168     if (ret != 0)
169         goto done;
170
171     r = sqlite3_step(stmt);
172     if (r != SQLITE_DONE) {
173         fprintf(stderr, "ERROR: could not insert playlist info: %s\n",
174                 sqlite3_errmsg(ldp->db));
175         ret = -4;
176         goto done;
177     }
178
179     ret = 0;
180
181   done:
182     lms_db_reset_stmt(stmt);
183
184     return ret;
185 }
186
187 int
188 lms_db_playlist_add(lms_db_playlist_t *ldp, struct lms_playlist_info *info)
189 {
190     if (!ldp)
191         return -1;
192     if (!info)
193         return -2;
194     if (info->id < 1)
195         return -3;
196
197     return _db_insert(ldp, info);
198 }