configure.ac: Move OpenAL to Audio Output Plugins (nonstreaming), add header.
[mpd-mk.git] / src / sticker.c
blobc59cdd078707699f47aa02f2f467bb4e6c0746ff
1 /*
2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "config.h"
21 #include "sticker.h"
22 #include "idle.h"
24 #include <glib.h>
25 #include <sqlite3.h>
26 #include <assert.h>
28 #undef G_LOG_DOMAIN
29 #define G_LOG_DOMAIN "sticker"
31 #if SQLITE_VERSION_NUMBER < 3003009
32 #define sqlite3_prepare_v2 sqlite3_prepare
33 #endif
35 struct sticker {
36 GHashTable *table;
39 enum sticker_sql {
40 STICKER_SQL_GET,
41 STICKER_SQL_LIST,
42 STICKER_SQL_UPDATE,
43 STICKER_SQL_INSERT,
44 STICKER_SQL_DELETE,
45 STICKER_SQL_DELETE_VALUE,
46 STICKER_SQL_FIND,
49 static const char *const sticker_sql[] = {
50 [STICKER_SQL_GET] =
51 "SELECT value FROM sticker WHERE type=? AND uri=? AND name=?",
52 [STICKER_SQL_LIST] =
53 "SELECT name,value FROM sticker WHERE type=? AND uri=?",
54 [STICKER_SQL_UPDATE] =
55 "UPDATE sticker SET value=? WHERE type=? AND uri=? AND name=?",
56 [STICKER_SQL_INSERT] =
57 "INSERT INTO sticker(type,uri,name,value) VALUES(?, ?, ?, ?)",
58 [STICKER_SQL_DELETE] =
59 "DELETE FROM sticker WHERE type=? AND uri=?",
60 [STICKER_SQL_DELETE_VALUE] =
61 "DELETE FROM sticker WHERE type=? AND uri=? AND name=?",
62 [STICKER_SQL_FIND] =
63 "SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=?",
66 static const char sticker_sql_create[] =
67 "CREATE TABLE IF NOT EXISTS sticker("
68 " type VARCHAR NOT NULL, "
69 " uri VARCHAR NOT NULL, "
70 " name VARCHAR NOT NULL, "
71 " value VARCHAR NOT NULL"
72 ");"
73 "CREATE UNIQUE INDEX IF NOT EXISTS"
74 " sticker_value ON sticker(type, uri, name);"
75 "";
77 static sqlite3 *sticker_db;
78 static sqlite3_stmt *sticker_stmt[G_N_ELEMENTS(sticker_sql)];
80 static GQuark
81 sticker_quark(void)
83 return g_quark_from_static_string("sticker");
86 static sqlite3_stmt *
87 sticker_prepare(const char *sql, GError **error_r)
89 int ret;
90 sqlite3_stmt *stmt;
92 ret = sqlite3_prepare_v2(sticker_db, sql, -1, &stmt, NULL);
93 if (ret != SQLITE_OK) {
94 g_set_error(error_r, sticker_quark(), ret,
95 "sqlite3_prepare_v2() failed: %s",
96 sqlite3_errmsg(sticker_db));
97 return NULL;
100 return stmt;
103 bool
104 sticker_global_init(const char *path, GError **error_r)
106 int ret;
108 if (path == NULL)
109 /* not configured */
110 return true;
112 /* open/create the sqlite database */
114 ret = sqlite3_open(path, &sticker_db);
115 if (ret != SQLITE_OK) {
116 g_set_error(error_r, sticker_quark(), ret,
117 "Failed to open sqlite database '%s': %s",
118 path, sqlite3_errmsg(sticker_db));
119 return false;
122 /* create the table and index */
124 ret = sqlite3_exec(sticker_db, sticker_sql_create, NULL, NULL, NULL);
125 if (ret != SQLITE_OK) {
126 g_set_error(error_r, sticker_quark(), ret,
127 "Failed to create sticker table: %s",
128 sqlite3_errmsg(sticker_db));
129 return false;
132 /* prepare the statements we're going to use */
134 for (unsigned i = 0; i < G_N_ELEMENTS(sticker_sql); ++i) {
135 assert(sticker_sql[i] != NULL);
137 sticker_stmt[i] = sticker_prepare(sticker_sql[i], error_r);
138 if (sticker_stmt[i] == NULL)
139 return false;
142 return true;
145 void
146 sticker_global_finish(void)
148 if (sticker_db == NULL)
149 /* not configured */
150 return;
152 for (unsigned i = 0; i < G_N_ELEMENTS(sticker_stmt); ++i) {
153 assert(sticker_stmt[i] != NULL);
155 sqlite3_finalize(sticker_stmt[i]);
158 sqlite3_close(sticker_db);
161 bool
162 sticker_enabled(void)
164 return sticker_db != NULL;
167 char *
168 sticker_load_value(const char *type, const char *uri, const char *name)
170 sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_GET];
171 int ret;
172 char *value;
174 assert(sticker_enabled());
175 assert(type != NULL);
176 assert(uri != NULL);
177 assert(name != NULL);
179 if (*name == 0)
180 return NULL;
182 sqlite3_reset(stmt);
184 ret = sqlite3_bind_text(stmt, 1, type, -1, NULL);
185 if (ret != SQLITE_OK) {
186 g_warning("sqlite3_bind_text() failed: %s",
187 sqlite3_errmsg(sticker_db));
188 return NULL;
191 ret = sqlite3_bind_text(stmt, 2, uri, -1, NULL);
192 if (ret != SQLITE_OK) {
193 g_warning("sqlite3_bind_text() failed: %s",
194 sqlite3_errmsg(sticker_db));
195 return NULL;
198 ret = sqlite3_bind_text(stmt, 3, name, -1, NULL);
199 if (ret != SQLITE_OK) {
200 g_warning("sqlite3_bind_text() failed: %s",
201 sqlite3_errmsg(sticker_db));
202 return NULL;
205 do {
206 ret = sqlite3_step(stmt);
207 } while (ret == SQLITE_BUSY);
209 if (ret == SQLITE_ROW) {
210 /* record found */
211 value = g_strdup((const char*)sqlite3_column_text(stmt, 0));
212 } else if (ret == SQLITE_DONE) {
213 /* no record found */
214 value = NULL;
215 } else {
216 /* error */
217 g_warning("sqlite3_step() failed: %s",
218 sqlite3_errmsg(sticker_db));
219 return NULL;
222 sqlite3_reset(stmt);
223 sqlite3_clear_bindings(stmt);
225 return value;
228 static bool
229 sticker_list_values(GHashTable *hash, const char *type, const char *uri)
231 sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_LIST];
232 int ret;
233 char *name, *value;
235 assert(hash != NULL);
236 assert(type != NULL);
237 assert(uri != NULL);
238 assert(sticker_enabled());
240 sqlite3_reset(stmt);
242 ret = sqlite3_bind_text(stmt, 1, type, -1, NULL);
243 if (ret != SQLITE_OK) {
244 g_warning("sqlite3_bind_text() failed: %s",
245 sqlite3_errmsg(sticker_db));
246 return false;
249 ret = sqlite3_bind_text(stmt, 2, uri, -1, NULL);
250 if (ret != SQLITE_OK) {
251 g_warning("sqlite3_bind_text() failed: %s",
252 sqlite3_errmsg(sticker_db));
253 return false;
256 do {
257 ret = sqlite3_step(stmt);
258 switch (ret) {
259 case SQLITE_ROW:
260 name = g_strdup((const char*)sqlite3_column_text(stmt, 0));
261 value = g_strdup((const char*)sqlite3_column_text(stmt, 1));
262 g_hash_table_insert(hash, name, value);
263 break;
264 case SQLITE_DONE:
265 break;
266 case SQLITE_BUSY:
267 /* no op */
268 break;
269 default:
270 g_warning("sqlite3_step() failed: %s",
271 sqlite3_errmsg(sticker_db));
272 return false;
274 } while (ret != SQLITE_DONE);
276 sqlite3_reset(stmt);
277 sqlite3_clear_bindings(stmt);
279 return true;
282 static bool
283 sticker_update_value(const char *type, const char *uri,
284 const char *name, const char *value)
286 sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_UPDATE];
287 int ret;
289 assert(type != NULL);
290 assert(uri != NULL);
291 assert(name != NULL);
292 assert(*name != 0);
293 assert(value != NULL);
295 assert(sticker_enabled());
297 sqlite3_reset(stmt);
299 ret = sqlite3_bind_text(stmt, 1, value, -1, NULL);
300 if (ret != SQLITE_OK) {
301 g_warning("sqlite3_bind_text() failed: %s",
302 sqlite3_errmsg(sticker_db));
303 return false;
306 ret = sqlite3_bind_text(stmt, 2, type, -1, NULL);
307 if (ret != SQLITE_OK) {
308 g_warning("sqlite3_bind_text() failed: %s",
309 sqlite3_errmsg(sticker_db));
310 return false;
313 ret = sqlite3_bind_text(stmt, 3, uri, -1, NULL);
314 if (ret != SQLITE_OK) {
315 g_warning("sqlite3_bind_text() failed: %s",
316 sqlite3_errmsg(sticker_db));
317 return false;
320 ret = sqlite3_bind_text(stmt, 4, name, -1, NULL);
321 if (ret != SQLITE_OK) {
322 g_warning("sqlite3_bind_text() failed: %s",
323 sqlite3_errmsg(sticker_db));
324 return false;
327 do {
328 ret = sqlite3_step(stmt);
329 } while (ret == SQLITE_BUSY);
331 if (ret != SQLITE_DONE) {
332 g_warning("sqlite3_step() failed: %s",
333 sqlite3_errmsg(sticker_db));
334 return false;
337 ret = sqlite3_changes(sticker_db);
339 sqlite3_reset(stmt);
340 sqlite3_clear_bindings(stmt);
342 idle_add(IDLE_STICKER);
343 return ret > 0;
346 static bool
347 sticker_insert_value(const char *type, const char *uri,
348 const char *name, const char *value)
350 sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_INSERT];
351 int ret;
353 assert(type != NULL);
354 assert(uri != NULL);
355 assert(name != NULL);
356 assert(*name != 0);
357 assert(value != NULL);
359 assert(sticker_enabled());
361 sqlite3_reset(stmt);
363 ret = sqlite3_bind_text(stmt, 1, type, -1, NULL);
364 if (ret != SQLITE_OK) {
365 g_warning("sqlite3_bind_text() failed: %s",
366 sqlite3_errmsg(sticker_db));
367 return false;
370 ret = sqlite3_bind_text(stmt, 2, uri, -1, NULL);
371 if (ret != SQLITE_OK) {
372 g_warning("sqlite3_bind_text() failed: %s",
373 sqlite3_errmsg(sticker_db));
374 return false;
377 ret = sqlite3_bind_text(stmt, 3, name, -1, NULL);
378 if (ret != SQLITE_OK) {
379 g_warning("sqlite3_bind_text() failed: %s",
380 sqlite3_errmsg(sticker_db));
381 return false;
384 ret = sqlite3_bind_text(stmt, 4, value, -1, NULL);
385 if (ret != SQLITE_OK) {
386 g_warning("sqlite3_bind_text() failed: %s",
387 sqlite3_errmsg(sticker_db));
388 return false;
391 do {
392 ret = sqlite3_step(stmt);
393 } while (ret == SQLITE_BUSY);
395 if (ret != SQLITE_DONE) {
396 g_warning("sqlite3_step() failed: %s",
397 sqlite3_errmsg(sticker_db));
398 return false;
401 sqlite3_reset(stmt);
402 sqlite3_clear_bindings(stmt);
405 idle_add(IDLE_STICKER);
406 return true;
409 bool
410 sticker_store_value(const char *type, const char *uri,
411 const char *name, const char *value)
413 assert(sticker_enabled());
414 assert(type != NULL);
415 assert(uri != NULL);
416 assert(name != NULL);
417 assert(value != NULL);
419 if (*name == 0)
420 return false;
422 return sticker_update_value(type, uri, name, value) ||
423 sticker_insert_value(type, uri, name, value);
426 bool
427 sticker_delete(const char *type, const char *uri)
429 sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE];
430 int ret;
432 assert(sticker_enabled());
433 assert(type != NULL);
434 assert(uri != NULL);
436 sqlite3_reset(stmt);
438 ret = sqlite3_bind_text(stmt, 1, type, -1, NULL);
439 if (ret != SQLITE_OK) {
440 g_warning("sqlite3_bind_text() failed: %s",
441 sqlite3_errmsg(sticker_db));
442 return false;
445 ret = sqlite3_bind_text(stmt, 2, uri, -1, NULL);
446 if (ret != SQLITE_OK) {
447 g_warning("sqlite3_bind_text() failed: %s",
448 sqlite3_errmsg(sticker_db));
449 return false;
452 do {
453 ret = sqlite3_step(stmt);
454 } while (ret == SQLITE_BUSY);
456 if (ret != SQLITE_DONE) {
457 g_warning("sqlite3_step() failed: %s",
458 sqlite3_errmsg(sticker_db));
459 return false;
462 sqlite3_reset(stmt);
463 sqlite3_clear_bindings(stmt);
465 idle_add(IDLE_STICKER);
466 return true;
469 bool
470 sticker_delete_value(const char *type, const char *uri, const char *name)
472 sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE_VALUE];
473 int ret;
475 assert(sticker_enabled());
476 assert(type != NULL);
477 assert(uri != NULL);
479 sqlite3_reset(stmt);
481 ret = sqlite3_bind_text(stmt, 1, type, -1, NULL);
482 if (ret != SQLITE_OK) {
483 g_warning("sqlite3_bind_text() failed: %s",
484 sqlite3_errmsg(sticker_db));
485 return false;
488 ret = sqlite3_bind_text(stmt, 2, uri, -1, NULL);
489 if (ret != SQLITE_OK) {
490 g_warning("sqlite3_bind_text() failed: %s",
491 sqlite3_errmsg(sticker_db));
492 return false;
495 ret = sqlite3_bind_text(stmt, 3, name, -1, NULL);
496 if (ret != SQLITE_OK) {
497 g_warning("sqlite3_bind_text() failed: %s",
498 sqlite3_errmsg(sticker_db));
499 return false;
502 do {
503 ret = sqlite3_step(stmt);
504 } while (ret == SQLITE_BUSY);
506 if (ret != SQLITE_DONE) {
507 g_warning("sqlite3_step() failed: %s",
508 sqlite3_errmsg(sticker_db));
509 return false;
512 ret = sqlite3_changes(sticker_db);
514 sqlite3_reset(stmt);
515 sqlite3_clear_bindings(stmt);
517 idle_add(IDLE_STICKER);
518 return ret > 0;
521 static struct sticker *
522 sticker_new(void)
524 struct sticker *sticker = g_new(struct sticker, 1);
526 sticker->table = g_hash_table_new_full(g_str_hash, g_str_equal,
527 g_free, g_free);
528 return sticker;
531 void
532 sticker_free(struct sticker *sticker)
534 assert(sticker != NULL);
535 assert(sticker->table != NULL);
537 g_hash_table_destroy(sticker->table);
538 g_free(sticker);
541 const char *
542 sticker_get_value(const struct sticker *sticker, const char *name)
544 return g_hash_table_lookup(sticker->table, name);
547 struct sticker_foreach_data {
548 void (*func)(const char *name, const char *value,
549 gpointer user_data);
550 gpointer user_data;
553 static void
554 sticker_foreach_func(gpointer key, gpointer value, gpointer user_data)
556 struct sticker_foreach_data *data = user_data;
558 data->func(key, value, data->user_data);
561 void
562 sticker_foreach(const struct sticker *sticker,
563 void (*func)(const char *name, const char *value,
564 gpointer user_data),
565 gpointer user_data)
567 struct sticker_foreach_data data = {
568 .func = func,
569 .user_data = user_data,
572 g_hash_table_foreach(sticker->table, sticker_foreach_func, &data);
575 struct sticker *
576 sticker_load(const char *type, const char *uri)
578 struct sticker *sticker = sticker_new();
579 bool success;
581 success = sticker_list_values(sticker->table, type, uri);
582 if (!success)
583 return NULL;
585 if (g_hash_table_size(sticker->table) == 0) {
586 /* don't return empty sticker objects */
587 sticker_free(sticker);
588 return NULL;
591 return sticker;
594 bool
595 sticker_find(const char *type, const char *base_uri, const char *name,
596 void (*func)(const char *uri, const char *value,
597 gpointer user_data),
598 gpointer user_data)
600 sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_FIND];
601 int ret;
603 assert(type != NULL);
604 assert(name != NULL);
605 assert(func != NULL);
606 assert(sticker_enabled());
608 sqlite3_reset(stmt);
610 ret = sqlite3_bind_text(stmt, 1, type, -1, NULL);
611 if (ret != SQLITE_OK) {
612 g_warning("sqlite3_bind_text() failed: %s",
613 sqlite3_errmsg(sticker_db));
614 return false;
617 if (base_uri == NULL)
618 base_uri = "";
620 ret = sqlite3_bind_text(stmt, 2, base_uri, -1, NULL);
621 if (ret != SQLITE_OK) {
622 g_warning("sqlite3_bind_text() failed: %s",
623 sqlite3_errmsg(sticker_db));
624 return false;
627 ret = sqlite3_bind_text(stmt, 3, name, -1, NULL);
628 if (ret != SQLITE_OK) {
629 g_warning("sqlite3_bind_text() failed: %s",
630 sqlite3_errmsg(sticker_db));
631 return false;
634 do {
635 ret = sqlite3_step(stmt);
636 switch (ret) {
637 case SQLITE_ROW:
638 func((const char*)sqlite3_column_text(stmt, 0),
639 (const char*)sqlite3_column_text(stmt, 1),
640 user_data);
641 break;
642 case SQLITE_DONE:
643 break;
644 case SQLITE_BUSY:
645 /* no op */
646 break;
647 default:
648 g_warning("sqlite3_step() failed: %s",
649 sqlite3_errmsg(sticker_db));
650 return false;
652 } while (ret != SQLITE_DONE);
654 sqlite3_reset(stmt);
655 sqlite3_clear_bindings(stmt);
657 return true;